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": "东柳小学,艾家小学"
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITzhongzi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值