• kityminder-editor + MongoDB 思维导图数据自动实时保存方案


    最近开始做自己的第一个开源项目:一个基于思维导图的测试用例管理系统MinderCase,在做了一周的技术调研后,决定采用kityminder-editor作为思维导图编辑器,为了支持实时存储,当思维导图内容变化时使用JSON-Patch计算出内容变化产生的diffPatches,然后将diffPatches传给后台映射为对应的MongoDB操作符,执行更新操作

    JSON-Patch是用来描述JSON数据变化的一种形式。使用它可以避免在JSON数据只发生部分修改时发送整个文档。与HTTP Patch方法是天造地设的一对,它允许以符合标准的方式对HTTP API进行部分更新。
    kityminder-editor使用JSON结构来存储数据,每个节点包括一个data字段表示节点本身的属性,children数组包含该节点的子节点,依次递归嵌套。在编辑思维导图的时候,最多的动作就是对节点的增、删、改,对于这种树形结构,借鉴传统关系型数据库的设计思路,可以使用节点引用的存储方法,参考MongoDB树形结构建模,但是在很多情况下,节点的增删查改会会引起大量的数据库操作,因此可以充分发挥MongoDB的优势,把整个JSON数据存储在一个document中。最终的存储结构很简单,除了数据库自动生成的_id_v字段,只有data字段表示完整的思维导图数据。

    {
        "_id": ObjectId("5b589668eac4d118dabf9546"),
        "data": {
            "root": {
                "data": {
                    "id": "bn5xbxbefk00",
                    "created": 1532532217325,
                    "text": "思维导图"
                },
                "children": [
                    {
                        "data": {
                            "id": "bna5hhbc6xc0",
                            "created": 1532961461384,
                            "text": "分支主题"
                        },
                        "children": [
                        ]
                    }
                ]
            },
            "template": "default",
            "theme": "fresh-blue",
            "version": "1.4.43"
        },
        "__v": NumberInt("0")
    }
    

    当思维导图内容发生变化时,会触contentchange事件,在这个事件中我们使用exportJson方法导出当前思维导图的JSON结构数据,与上一次保存的数据进行JSON Diff,生成diffPatches,如下所示,删除一个节点引发的数据变化,可以使用diffPatches操作数组表示。

    window.editor.minder.on("contentchange", () => {
        const newMinderData = minder.exportJson();
        const diffPatches = compare(oldMinderData, newMinderData);
        this.minderData = newMinderData;
        diffPatches.length > 0 &&
            axios
                .patch(`/minder/${id}`, diffPatches)
                .then(function(response) {
                    oldMinderData = newMinderData;
                    console.log(response);
                })
                .catch(function(error) {
                    console.log(error);
                });
    });
    
    



    后台在接收到前端传来的diffPatches后,将其映射为MongoDB的操作符,比如addreplace操作可以映射为$set操作,remove可以映射为$unset操作,目前为止,我发现kityminder-editor的操作引发的diff仅限这三种操作。

    const diffPatches = ....;
    const opMap = {
        add: "$set",
        replace: "$set",
        remove: "$unset"
    };
    const diffPatches = ctx.request.body; //
    const update = {};
    diffPatches.reduce((prev, cur) => {
        const { op, path, value = 1 } = cur;
        if (!prev[opMap[op]]) {
            prev[opMap[op]] = {};
        }
        prev[opMap[op]][`data${path.replace(///g, ".")}`] = value;
        return prev;
    }, update);
    

    实践过程中发现remove操作映射成$unset操作会有一些问题,当进行删除操作是,对应的patch操作是没有value的,上面给了一个默认值为1,该操作映射为$unset执行后,对应对象字段或者数组元素会变成null,如下图所示。

    实践过程中发现对象字段变为null,如上图中的priority字段变成null,对思维导图的渲染不会产生影响,但是子节点数组children数组中包含null元素会导致思维导图加载失败。实际上MongoDB对于数组的元素的删除有其对应的操作符$pull,遗憾的是该操作符并不能根据数组索引来删除数组,关于这方面的具体问题可以参考In mongoDb, how do you remove an array element by its index,总的来说,目前没有好的方法解决这个问题,即使我尝试修改产生diffPatches的代码,给remove操作添加上value字段,当一个操作引发对个patch时,在更新数据库时可能会发生冲突导致更新失败。因此只能“曲线救国”,在读取思维导图数据时,递归遍历所有节点的子节点数组,过滤除null值,这样在渲染整个思维导图数据时就不会发生错误。考虑到读取数据的实时性要求不高,而修改数据实时保存实时性要求比较高,这个方案还是可以接受的。

    function isValidArr(arr) {
        return Array.isArray(arr) && arr.length;
    }
    function removeInvalidChild(node = {}){
        const { children } = node || {};
        if(isValidArr(children)){
            node.children = children.filter((item) => {
                removeInvalidChild(item);
                return item;
            })
        }
    }
    removeInvalidChild(root); 
    

    到此为止,所有的技术论证都已完成,下一步就是现实整个系统了。

  • 相关阅读:
    centos7 yum安装配置Lnmp和负载配置
    Linux搭建lamp(Apache+PHP+Mysql环境)centos7.2版详细教程
    php的移位符运算
    Mysql的注入与防御
    介绍10个非常有用的PHP函数
    PHP性能的分析
    Netty 4源码解析:服务端启动
    centOS6.6升级gcc4.8
    kafka 0.8.x producer Example(scala)
    spark standalone zookeeper HA部署方式
  • 原文地址:https://www.cnblogs.com/star91/p/kitymindereditor--MongoDB-si-wei-dao-tu-shu-ju-zi-.html
Copyright © 2020-2023  润新知