• js数据过滤算法搭建


    需求描述

    公司需要搭建一个paas平台兼容所有的硬件,硬件把自己采集到的数据发送到paas平台,paas平台把数据处理之发送到各个服务。很多时候硬件发送的数据量特别大,很多不是我们需要的,这个时候,我们把全部的数据进行转发的话,就会浪费大量的带宽,所以,我们需要选择需要的数据进行发送,数据过滤算法便是由此而来。

    实现思路

    技术: 原生js + elementplus的 Tree树形控件(主要用来显示)

    1. 按照一定的规则把硬件发送的对象拆分成一个一个的属性
    2. 对每一个属性进行标记【类型,父元素,所在的节点id等】
    3. 标记完成之后,把生成标记对象树传入tree树形控件以生成可视化页面
    4. 把标记树用json的形式存入数据库,或者redis缓存
    5. 把每个过滤规则和硬件绑定或者和硬件所在的组绑定
    6. 当硬件发送过数据来的时候,自动根据该硬件的过滤规则(即:标记树),把需要的数据组合成一个新的对象并发送给对应的服务。

    标记树的结构,是根据elementPlus的tree组件要求而搭建的,根据tree的要求传入一个对象,便可以生成可视化的选择树,标记树的结构就是根据这个创建的,也可以用其他形式,不过思想都是一样的

    实现代码
    • 把硬件数据拆分属性,并生成 标记树
    
    /**
     * 数据过滤算法----合成属性 树(后期会根据属性树入库、生成对象)
     * @param {*} jsonData 
     * @param {*} respTreeData 
     * @param {*} level 
     * @returns 
     */
    export const makePropertityTree = (jsonData, respTreeData, level) => {
        if (!respTreeData || !jsonData) {
            console.error("参数传递出现错误!!")
            return;
        }
        if (judgeType(jsonData) === "[object Object]") {
            // 对象类型
            Reflect.ownKeys(jsonData).forEach((val, idx, arr) => {
                let tmpId = (level ? level : "") + "" + idx + val
                let tmpObj = {
                    id: tmpId,
                    label: val,
                    type: judgeType(jsonData[val]),
                    path: [],
                    children: []
                }
    
                if (level) {
                    tmpObj.path = [...respTreeData.path, tmpId]
                    respTreeData.children.push(tmpObj)
                } else {
                    tmpObj.path.push(tmpId)
                    respTreeData.push(tmpObj)
                }
                if (judgeType(jsonData[val]) == "[object Object]") {
                    makePropertityTree(jsonData[val], tmpObj, level ? level + 1 : 1)
                }
            })
    
        } else {
            // 如果参数类型不是 Object 直接原样传递,不做处理
            // 非对象类型
            let tmpObj = {
                id: "all",
                label: "all",
                type: judgeType(jsonData),
                path: [],
                children: []
            }
    
            respTreeData.push(tmpObj)
        }
    }
    
    • 根据 标记树 过滤硬件的数据包,并生成需要的对象
    
    /**
     * 根据属性树treeRef生成过滤对象
     * @param {*} treeRef  elemengplus 选择树 组件
     * @param {*} requestData  需要过滤的数据
     * 
     * example: 
     * 
     * // 节点选择树 
     * const treeRef = ref(null);
     * const getCheckedNodes = () => {
     *  let filterData = filterPropertityObjByTreeRef(treeRef, testJson);
     *  console.log(filterData)
     * }
     */
    export const filterPropertityObjByTreeRef = (treeRef, requestData) => {
    
        let nodeList = treeRef.value.getCheckedNodes(false, false)
        let modelRuleObj = {};
        nodeList.forEach((val, idx) => {
        
            if(val.id == "all") {
                // 如果选择了全部属性,或者不过滤,直接返回对象所有属性。
                modelRuleObj = requestData;
                return;
            }
            let tmpPropertityObj = {};
            let tmpMiddleSaveObj = {};
            let targetPropertityObj = {};
            for (let i = 0; i < val.path.length; i++) {
                // 根据node key 循环 拿到 该属性的所有父节点
                let tmpNode = treeRef.value.getNode(val.path[i]).data
                let pathLen = val.path.length;
    
                if (i == 0) {
                    if (!tmpPropertityObj[tmpNode.label] && i != (pathLen - 1)) {
                        if (tmpNode.type == "[object Object]") {
                            tmpPropertityObj[tmpNode.label] = {};
                            tmpMiddleSaveObj = tmpPropertityObj[tmpNode.label];
                        }
                    }
                } else {
                    if (i != (pathLen - 1)) {
                        if (!tmpMiddleSaveObj[tmpNode.label]) {
                            tmpMiddleSaveObj[tmpNode.label] = {};
                        }
                        tmpMiddleSaveObj = tmpMiddleSaveObj[tmpNode.label];
                    }
                }
    
                if (i == 0) {
                    targetPropertityObj[tmpNode.label] = requestData[tmpNode.label]
                }
                targetPropertityObj = targetPropertityObj[tmpNode.label]
    
    
                if (i == (val.path.length - 1)) {
                    if (val.path.length == 1) {
                        tmpPropertityObj[val.label] = targetPropertityObj
                    } else {
                        if (judgeType(targetPropertityObj) != "[object Object]") {
                            // 最后一个属性直接赋值
                            tmpMiddleSaveObj[val.label] = targetPropertityObj
                        }
    
                    }
                }
            }
            modelRuleObj = mergeObjDeep(modelRuleObj, tmpPropertityObj)
    
        });
        // 过滤后的对象
        return modelRuleObj;
    }
    
    
    
    • 类型判断函数 (用到的工具方法)
    /**
     * [object String] 字符串
     * [object Number] 数字类型
     * [object Array] 数组
     * [object Date] 日期
     * [object Function] 函数
     * [object Object] 对象
     * @param {*} data 
     * @returns 
     */
    export const judgeType = (data) => {
        return Object.prototype.toString.call(data);
    }
    
    
    • 深度融合对象函数 (用到的工具方法)
    /**
     * 深度融合两个对象
     * ... 合并对象只是简单地,浅层次的合并
     * @param {*} targetObj 
     * @param {*} sourceObj 
     * @returns 
     */
    export const mergeObjDeep = (targetObj, sourceObj) => {
        
        Reflect.ownKeys(sourceObj).forEach((val, idx, arr) => {
        
            if (targetObj[val]) {
                if (judgeType(sourceObj[val]) == "[object Object]") {
                    mergeObjDeep(targetObj[val], sourceObj[val]);
                } else {
                    targetObj[val] = sourceObj[val]
                }
            } else {
                targetObj[val] = sourceObj[val]
            }
    
        })
        return targetObj;
    }
    
    
    使用案例
    • 使用案例
    import { makePropertityTree, filterPropertityObjByTreeRef } from "@/utils/propertityFilter.js"
    let treeData = reactive([]);
    // 生成标记树
    makePropertityTree(testJson, treeData);
    console.log("treeData", treeData);
    console.log("testJson", testJson)
    
    // 节点选择树
    const treeRef = ref(null);
    const getCheckedNodes = () => {
      // 根据标记树 生成过滤后的对象
      let filterData = filterPropertityObjByTreeRef(treeRef, testJson);
      console.log(filterData)
    }
    
    • 效果展示

    在这里插入图片描述

    • 测试json数据
    
        {
            "name": "张三",
            "age": 18,
            "hobby": {
                "exercise": {
                    "ball": [
                        "basketball",
                        "pingpang"
                    ],
                    "running": [
                        "long-distance race",
                        "short"
                    ]
                },
                "reading": {
                    "moyan": {
                        "bookName": "平凡的世界",
                        "price": 200,
                        "priz e": true,
                        "bookDetail": {
                            "totalNumber": "20万字",
                            "year": "2004年出版",
                            "author": "莫言"
                        }
                    }
                }
            },
            "family": [
                "father",
                "mother",
                "wife",
                "son",
                "me"
            ],
            "school": {
                "bigSchool": "烟台大学",
                "highSchool": "广饶一中",
                "baseSchool": "李鹊镇初级中学",
                "smallSchool": "东柳小学,艾家小学"
            }
        }
    
    
  • 相关阅读:
    『现学现忘』Docker基础 — 22、使用Docker安装Nginx
    Java架构师学习路线
    数学建模--智能算法之鱼群算法
    RDMA技术(解决主从数据库数据不一致问题)
    艾美捷SequENZ测序级改造型胰蛋白酶用途和技术说明
    开源ERP和CRM套件Dolibarr
    电力行业放大招了!赶紧学起来
    文件上传功能实现
    React 与 TS 结合使用时组件传参总结
    算法基础课
  • 原文地址:https://blog.csdn.net/ITzhongzi/article/details/126956218