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

本贴最后更新于 287 天前,其中的信息可能已经水流花落

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

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


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

image.png

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

image.png


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

  • 思源笔记

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

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

    28448 引用 • 119792 回帖
  • Q&A

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

    11156 引用 • 50667 回帖 • 52 关注

相关帖子

被采纳的回答
  • 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

    不知道是不是我代码改的不对,这是错误的录屏:

    20250311173219.gif

    另外可以正确导出表格的数据库,新增数据后,新增的数据直接出现在表格的第一个格里,也没有出现在相应的格子 😂

  • auric

    哈喽,w 佬,我看了 GitHub 上的 issue,这个问题好解决么,不好解决的话,我今天发现直接新建数据库,不要改动排序,输入的内容不会有太大问题 😂 ,就是用的时候需要小心 😂

    1 回复
  • 是的,就是渲染数据和存储数据不一致导致的。这个要改成读渲染数据。这两种数据格式完全不一样,由于是底层,上层依赖较多,修改后影响较大,要做中间兼容层,改动较麻烦。

    2 回复
  • 查看全部回帖

推荐标签 标签

  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 1 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    950 引用 • 1460 回帖 • 2 关注
  • Visio
    1 引用 • 2 回帖 • 1 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 458 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    6 引用 • 26 回帖 • 559 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    182 引用 • 400 回帖 • 1 关注
  • Access
    1 引用 • 3 回帖 • 14 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    99 引用 • 367 回帖
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1062 引用 • 3456 回帖 • 124 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    337 引用 • 324 回帖 • 4 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    27 引用 • 7 回帖 • 93 关注
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    561 引用 • 677 回帖
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    14 引用 • 84 回帖 • 1 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 150 回帖 • 1 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    39 引用 • 170 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    293 引用 • 4496 回帖 • 688 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 623 关注
  • 创业

    你比 99% 的人都优秀么?

    81 引用 • 1396 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 565 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 2 关注
  • 大数据

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

    91 引用 • 113 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 724 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖