求助将数据库中的内容渲染为表格

求助一个将数据库内容渲染为表格的方法

起因是看到了这一篇帖子利用 数据库 和 Chart(图表) 做小朋友身高管理 - 链滴,就想着是否有方法可以将数据库中的内容做成表格。


比如有这样一个数据库,每个主键有横坐标(A-B)和纵坐标(1-9)两个字段。

image.png

是否可以根据每个主键的横坐标和纵坐标两个字段,通过图表渲染成类似下面这种表格呢?感觉做一个物品管理蛮有意思的,数据库中添加其他字段描述物品信息,根据表格找到物品存放位置或者坐标(比如中药柜)

image.png


大家有什么好的方法吗(代码这方面我是真没时间学,之前也没接触过 😂)

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    24775 引用 • 101880 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9391 引用 • 42802 回帖 • 112 关注

相关帖子

被采纳的回答
  • wilsons 3 1 赞同

    那个帖子是根据 [js] 图表如何和表格联动 - wilsons 的回帖 这个改造的,这种方式需要自己手动解析数据库 json 数据,较为麻烦。

    建议使用简单查询,实现起来更方便,可参考 震惊,思源表格和数据库竟然可以用 SQL 查询

    然后,分别新建一个数据和表格,并复制数据库块 id 和表格块 id,然后在当前文档输入 {{}} 在弹出的对话框中,输入以下代码,并把刚才复制的 id 填入到下面的相应参数中即可

    //!js
    
    // 数据库块id
    const avBlockId = '20250311063435-9066xpv';
    
    // 表格块id
    const tableBlockId = '20250311063452-p03kxva';
    
    // 数据库变更后自动更新延迟,单位是毫秒,默认是1秒,0则不自动更新
    // 注意:更新该参数后需要刷新页面才能生效
    const autoFreshDelay = 1000;
    
    // 监听数据库变化
    observeAvChange();
    
    return query(
        "select * from ?",
        [fromAv(avBlockId), item],
        '',
        ({ rawData, updateTable, renderSuccess }) => {
            let tableData = transformData(rawData);
            tableData = toMarkdownTable(tableData);
            updateTable(tableBlockId, tableData);
            return renderSuccess('更新完成', item);
        }
    );
    
    function toMarkdownTable(data) {
        // 提取所有列名(包括空列 "")
        const columns = Array.from(
            data.reduce((set, row) => {
                Object.keys(row).forEach(key => set.add(key));
                return set;
            }, new Set())
        ).sort((a, b) => (a === "" ? -1 : a.localeCompare(b))); // 确保空列 "" 在最前面
    
        // 构造表头行
        const headerRow = `| ${columns.map(col => (col === "" ? "" : col)).join(" | ")} |`;
    
        // 构造分隔符行
        const separatorRow = `| ${columns.map(() => "---").join(" | ")} |`;
    
        // 构造数据行
        const dataRows = data.map(row => {
            return `| ${columns.map(col => row[col] || "").join(" | ")} |`;
        });
    
        // 拼接所有部分
        return [headerRow, separatorRow, ...dataRows].join("\n");
    }
    
    function transformData(input) {
        // 创建一个 Map 来按横坐标分组
        const groupedData = new Map();
    
        // 遍历输入数组,按横坐标分组
        input.forEach(item => {
            const { 主键, 横坐标, 纵坐标 } = item;
    
            // 如果横坐标不存在于 Map 中,则初始化
            if (!groupedData.has(横坐标)) {
                groupedData.set(横坐标, { "": 横坐标 });
            }
    
            // 将纵坐标和主键添加到对应的横坐标分组中
            groupedData.get(横坐标)[纵坐标] = 主键;
        });
    
        // 将 Map 转换为数组并返回
        return Array.from(groupedData.values());
    }
    
    function observeAvChange() {
        // 监听av变化,当数据库块被修改时,重新获取数据
        if(autoFreshDelay > 0 && !window['__table_observe__' + avBlockId]) {
            window['__table_observe__' + avBlockId] = observeDOMChanges(document.querySelector('div[data-node-id="'+avBlockId+'"]'), ()=>{
                setTimeout(() => {
                    item.querySelector('.protyle-action__reload').click();
                }, 100);
            }, autoFreshDelay, {attributes: false});
        }
    }
    
    // 监听dom变化
    function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
        // 默认配置
        const defaultOptions = {
          attributes: true,
          childList: true,
          subtree: true,
        };
    
        // 合并默认配置与传入的配置
        const config = Object.assign({}, defaultOptions, options);
    
        // 创建一个观察器实例
        const observer = new MutationObserver((mutationsList) => {
            // 使用防抖函数确保单位时间内最多只调用一次回调
            if(window['__table_observeTimer__' + avBlockId]) {
                clearTimeout(window['__table_observeTimer__' + avBlockId]);
            }
            window['__table_observeTimer__' + avBlockId] = setTimeout(() => {
                // 处理变化
                callback(mutationsList);
            }, debounceTime);
        });
    
        // 开始观察目标节点
        observer.observe(targetNode, config);
    
        // 返回一个函数,以便在不需要时能够停止观察
        return () => {
          observer.disconnect();
        };
    }
    

    r118.gif

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • wilsons 3 1 赞同

    那个帖子是根据 [js] 图表如何和表格联动 - wilsons 的回帖 这个改造的,这种方式需要自己手动解析数据库 json 数据,较为麻烦。

    建议使用简单查询,实现起来更方便,可参考 震惊,思源表格和数据库竟然可以用 SQL 查询

    然后,分别新建一个数据和表格,并复制数据库块 id 和表格块 id,然后在当前文档输入 {{}} 在弹出的对话框中,输入以下代码,并把刚才复制的 id 填入到下面的相应参数中即可

    //!js
    
    // 数据库块id
    const avBlockId = '20250311063435-9066xpv';
    
    // 表格块id
    const tableBlockId = '20250311063452-p03kxva';
    
    // 数据库变更后自动更新延迟,单位是毫秒,默认是1秒,0则不自动更新
    // 注意:更新该参数后需要刷新页面才能生效
    const autoFreshDelay = 1000;
    
    // 监听数据库变化
    observeAvChange();
    
    return query(
        "select * from ?",
        [fromAv(avBlockId), item],
        '',
        ({ rawData, updateTable, renderSuccess }) => {
            let tableData = transformData(rawData);
            tableData = toMarkdownTable(tableData);
            updateTable(tableBlockId, tableData);
            return renderSuccess('更新完成', item);
        }
    );
    
    function toMarkdownTable(data) {
        // 提取所有列名(包括空列 "")
        const columns = Array.from(
            data.reduce((set, row) => {
                Object.keys(row).forEach(key => set.add(key));
                return set;
            }, new Set())
        ).sort((a, b) => (a === "" ? -1 : a.localeCompare(b))); // 确保空列 "" 在最前面
    
        // 构造表头行
        const headerRow = `| ${columns.map(col => (col === "" ? "" : col)).join(" | ")} |`;
    
        // 构造分隔符行
        const separatorRow = `| ${columns.map(() => "---").join(" | ")} |`;
    
        // 构造数据行
        const dataRows = data.map(row => {
            return `| ${columns.map(col => row[col] || "").join(" | ")} |`;
        });
    
        // 拼接所有部分
        return [headerRow, separatorRow, ...dataRows].join("\n");
    }
    
    function transformData(input) {
        // 创建一个 Map 来按横坐标分组
        const groupedData = new Map();
    
        // 遍历输入数组,按横坐标分组
        input.forEach(item => {
            const { 主键, 横坐标, 纵坐标 } = item;
    
            // 如果横坐标不存在于 Map 中,则初始化
            if (!groupedData.has(横坐标)) {
                groupedData.set(横坐标, { "": 横坐标 });
            }
    
            // 将纵坐标和主键添加到对应的横坐标分组中
            groupedData.get(横坐标)[纵坐标] = 主键;
        });
    
        // 将 Map 转换为数组并返回
        return Array.from(groupedData.values());
    }
    
    function observeAvChange() {
        // 监听av变化,当数据库块被修改时,重新获取数据
        if(autoFreshDelay > 0 && !window['__table_observe__' + avBlockId]) {
            window['__table_observe__' + avBlockId] = observeDOMChanges(document.querySelector('div[data-node-id="'+avBlockId+'"]'), ()=>{
                setTimeout(() => {
                    item.querySelector('.protyle-action__reload').click();
                }, 100);
            }, autoFreshDelay, {attributes: false});
        }
    }
    
    // 监听dom变化
    function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
        // 默认配置
        const defaultOptions = {
          attributes: true,
          childList: true,
          subtree: true,
        };
    
        // 合并默认配置与传入的配置
        const config = Object.assign({}, defaultOptions, options);
    
        // 创建一个观察器实例
        const observer = new MutationObserver((mutationsList) => {
            // 使用防抖函数确保单位时间内最多只调用一次回调
            if(window['__table_observeTimer__' + avBlockId]) {
                clearTimeout(window['__table_observeTimer__' + avBlockId]);
            }
            window['__table_observeTimer__' + avBlockId] = setTimeout(() => {
                // 处理变化
                callback(mutationsList);
            }, debounceTime);
        });
    
        // 开始观察目标节点
        observer.observe(targetNode, config);
    
        // 返回一个函数,以便在不需要时能够停止观察
        return () => {
          observer.disconnect();
        };
    }
    

    r118.gif

    3 回复
    2 操作
    wilsons 在 2025-03-11 09:50:26 更新了该回帖
    wilsons 在 2025-03-11 09:46:42 更新了该回帖
  • 其他回帖
  • auric

    w 佬,现在的这个方法,只要渲染好了,修改条目的字段内容时不会有影响,如果在没有内容的条目字段里输入,就会渲染到表格的第一个空格内 😂 ,不过这个方法对我目前的需求来讲算不上很难接受,再次谢谢 w 佬提供的这些 ❤️

  • 这个插件可能可以,但我完全不知道怎么用:

    image.png

    1 回复
  • auric

    测试.sy.zip 这是我测试好像有问题的文件,根据字段的插入块相应位置的代码。然后我用另外的两个数据库和表格,能够正确渲染到表格,但是添加之后就不能显示在正常的表格对应位置。

    1 回复
  • 查看全部回帖

推荐标签 标签

  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 608 关注
  • danl
    164 关注
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖 • 8 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 53 关注
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 272 关注
  • Office

    Office 现已更名为 Microsoft 365. Microsoft 365 将高级 Office 应用(如 Word、Excel 和 PowerPoint)与 1 TB 的 OneDrive 云存储空间、高级安全性等结合在一起,可帮助你在任何设备上完成操作。

    5 引用 • 34 回帖
  • sts
    2 引用 • 2 回帖 • 225 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖 • 1 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    427 引用 • 1250 回帖 • 597 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 32 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 4 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 368 关注
  • OneDrive
    2 引用 • 3 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 485 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    87 引用 • 122 回帖 • 622 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1278 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 459 关注
  • AWS
    11 引用 • 28 回帖 • 10 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    226 引用 • 476 回帖
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 6 关注
  • 自由行
    2 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 2 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖