简体   繁体   English

使用Javascript中的键过滤对象数组(node.js)

[英]Filtering array of object using key in Javascript (node.js)

Please anyone can help, I want to filter data based on key in node.js, I've tried most of things, but didn't worked.请任何人都可以提供帮助,我想根据 node.js 中的键过滤数据,我已经尝试了大部分事情,但没有奏效。 Below example data which needs to be filtered.下面是需要过滤的示例数据。 I could able to filter key:value pair, nested Json object but filtering Array of json object is not working.我可以过滤键:值对、嵌套的 Json 对象,但过滤 json 对象数组不起作用。 Eg var data =例如 var 数据 =

[{
    "createdBy":"Tom"
    "logistics" : 0,
    "paymentStatus" : "Paid",
    "orderAmount" : 5393.75,
    "details" : {
         "street": "S.S road",
         "postCOde": "440111",
    },
    "subOrders" : [
        {
        "name" : "sub Product1",
        "mrp" : 12,
        "details": "desk"
        },
        {
        "name" : "subProduct2",
        "mrp" : 89,
        "details": "chair"
        }
    ]
}]

result object should be filtered based on given permission array应根据给定的权限数组过滤结果对象

var permissionArray = ['logistics','paymentStatus','details.street','subOrders.name','subOrders.details'];

filtered result should look like过滤结果应该看起来像

{
   result = [{
        "logistics" : 0,
        "paymentStatus" : "Paid",
        "details" : {
             "street": "S.S road",
        },
        "subOrders" : [
            {
               "name" : "sub Product1",
               "details" : "desk"
            },
            {
               "name" : "sub Product1",
               "details" : "chair"
             }
         ]
}]
}

Building on @radulle's answer to allow the 'details.name' dot notation desired:以@radulle 的回答为基础,允许使用所需的“details.name”点符号:

(Also updated to now allow multiple subfields of one field - like 'subOrders.name' and 'subOrders.details') (也更新为现在允许一个字段的多个子字段 - 如 'subOrders.name' 和 'subOrders.details')

 var arr = [{ "createdBy":"Tom", "logistics" : 0, "paymentStatus" : "Paid", "orderAmount" : 5393.75, "details" : { "street": "SS road", "postCode": "440111" }, "subOrders" : [ { "name" : "sub Product1", "mrp" : 12, "details": "desk" }, { "name" : "subProduct2", "mrp" : 89, "details": "chair" } ] }] var permissionArray = ['logistics','paymentStatus','details.street', 'details.postCode','subOrders.name', 'subOrders.details']; var arrFiltered = arr.map(el => { let newEl = {} for (let elm of permissionArray){ if (elm.includes('.')){ //console.log(elm); const split_arr = elm.split('.') //console.log(el[split_arr[0]]); if (el[split_arr[0]] instanceof Array){ if (!newEl.hasOwnProperty([split_arr[0]]) ){ newEl[split_arr[0]] = el[split_arr[0]].map((child,index) => ({[split_arr[1]]: child[split_arr[1]]}) ) } else { el[split_arr[0]].forEach((child,index) => { //console.log(child[ split_arr[1] ]); newEl[split_arr[0]][index][split_arr[1]] = child[split_arr[1]]; }) } } else{ if (!newEl.hasOwnProperty([split_arr[0]]) ){ newEl[split_arr[0]] = {[split_arr[1]]: el[split_arr[0]][split_arr[1]]} } else { newEl[split_arr[0]][split_arr[1]] = el[split_arr[0]][split_arr[1]]; } } } else { newEl[elm] = el[elm]; } } return newEl; } ) console.log(arrFiltered)
 .as-console-wrapper { max-height: 100% !important; top: 0; }

NOTE: you need to check first if a dot is included with elm.includes('.') , then you have to split it into its two parts with elm.split('.') , then finally you need to check if the value of the key is an array, like 'subOrders' or if it is just an object like 'details' and handle each case with either directly calling the child key, or mapping over the array and calling the child key.注意:您需要先确认一下,一个点是包含在elm.includes('.')那么你必须把它与分成了两个部分elm.split('.')那么最后你需要检查键的值是一个数组,如“subOrders”,或者它只是一个像“details”这样的对象,并通过直接调用子键或映射数组并调用子键来处理每种情况。

With the permission array as:权限数组为:

var permissionArray = ['logistics','paymentStatus','details.street', 'details.postCode','subOrders.name', 'subOrders.details'];

The output is:输出是:

[
  {
    "logistics": 0,
    "paymentStatus": "Paid",
    "details": {
      "street": "S.S road",
      "postCode": "440111"
    },
    "subOrders": [
      {
        "name": "sub Product1",
        "details": "desk"
      },
      {
        "name": "subProduct2",
        "details": "chair"
      }
    ]
  }
]

NOTE: upon request of the OP, this now also allows you to have two subfields of one field like 'subOrders.name', 'subOrders.details'注意:根据 OP 的要求,这现在还允许您拥有一个字段的两个子字段,例如'subOrders.name', 'subOrders.details'

For this !newEl.hasOwnProperty([split_arr[0]]) is used to check if the property/key doesn't already exist.为此!newEl.hasOwnProperty([split_arr[0]])用于检查属性/键是否尚不存在。 If it does not, then create it, but if it does, then modify this existing property/key's value/item.如果没有,则创建它,但如果有,则修改此现有属性/键的值/项目。

You could take a two step approach where you group same keys in an array and store the nested properties as well to the grouped parents.您可以采用两步法,将相同的键分组在一个数组中,并将嵌套的属性也存储到分组的父项中。

This is important if you have same parent keys, like如果您有相同的父键,这很重要,例如

['subOrders.name', 'subOrders.mrp']

For example a grouped array looks like this:例如,分组数组如下所示:

[
    [
        "logistics"
    ],
    [
        "paymentStatus"
    ],
    [
        "details",
        ["street"]
    ],
    [
        "subOrders",
        ["name", "mrp"]
    ]
]

Then build new objects based on the key and nested keys.然后根据键和嵌套键构建新对象。

 function filter(keys) { var pathes = keys.reduce((r, path) => { var [key, ...rest] = path.split('.'), temp = r.find(([q]) => q === key); if (rest.length) if (temp) temp[1].push(rest.join('.')); else r.push([key, [rest.join('.')]]); else if (!temp) r.push([key]); return r; }, []); return function (object) { const keys = pathes.filter(([key]) => key in object); return Object.fromEntries(keys.map(([key, rest]) => [ key, rest ? Array.isArray(object[key]) ? object[key].map(filter(rest)) : filter(rest)(object[key]) : object[key] ])); }; } var permissionArray = ['foo', 'logistics', 'paymentStatus', 'details.street', 'subOrders.name'], data = [{ createdBy: "Tom", logistics: 0, paymentStatus: "Paid", orderAmount: 5393.75, details: { street: "SS road", postCOde: "440111", }, subOrders: [{ name: "sub Product1", mrp: 12 }, { name: "subProduct2", mrp: 89 }] }], result = data.map(filter(permissionArray)); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Instead of building a filtered output, we may operate on original obj and remove its props.我们可以对原始 obj 进行操作并删除其道具,而不是构建过滤输出。

The permissions represent a tree (or trie if node is a word (. delimited))权限代表一棵树(或者如果节点是一个单词(。分隔)

If we further assume that any specified path is accessible in data, then any leaf has for parent an array or object (and so forth).如果我们进一步假设任何指定的路径都可以在数据中访问,那么任何叶子都有一个数组或对象作为父对象(等等)。

We then build a tree, and for any node traverse data and remove the keys which are not part of our specification.然后我们构建一棵树,并为任何节点遍历数据并删除不属于我们规范的一部分的键。

 const data = {"createdBy":"Tom","logistics":0,"paymentStatus":"Paid","orderAmount":5393.75,"details":{"street":"SS road","postCOde":"440111"},"subOrders":[{"name":"sub Product1","mrp":12},{"name":"subProduct2","mrp":89}],"a":{"b":[{"c":3,"d":"a"},{"c":4,"e":"f"}]}} const d = JSON.parse(JSON.stringify(data)) // do not mutate original const v = ['logistics','paymentStatus','details.street','subOrders.name','subOrders.details','abc'] const tree = v.map(x => x.split('.')).reduce((o, p) => { p.reduce((c, x) => (c[x] = c[x] || {}), o) return o },{}) function rec (keep, node) { if (Object.keys(keep).length === 0) return if (Array.isArray(node)) { return node.forEach(rec.bind(0, keep)) } for (const k in node) { !(k in keep) ? delete node[k] : rec(keep[k], node[k]) } } rec(tree, d) console.log(JSON.stringify(d,null,2))

You can maybe do it like this:你也许可以这样做:

 var arr = [{ "createdBy":"Tom", "logistics" : 0, "paymentStatus" : "Paid", "orderAmount" : 5393.75, "details" : { "street": "SS road", "postCOde": "440111" }, "subOrders" : [ { "name" : "sub Product1", "mrp" : 12 }, { "name" : "subProduct2", "mrp" : 89 } ] }] var permissionArray = ['logistics','paymentStatus','details'] var arrFiltered = arr.map(el => { let newEl = {} for (let elm of permissionArray) newEl[elm] = el[elm] return newEl } ) console.log(arrFiltered)

In the following solution, we divide the handling of objects and plain arrays.在下面的解决方案中,我们将对象和普通数组的处理分开。

We build-up a "qualified key" corresponding to the equivalent string in the permissions array, as we recursively descend into an object along its properties.当我们沿着对象的属性递归地下降到对象时,我们构建了一个与权限数组中的等效字符串相对应的“限定键”。

If we hit a primitive value, then we end the recursion for that property.如果我们命中一个原始值,那么我们结束对该属性的递归。

A new object sanitized is created for each level of the recursion to contain only the permitted properties.新对象sanitized为递归的每个层次仅包含所允许的属性来创建。

 const data = [{ "createdBy": "Tom", "logistics": 0, "paymentStatus": "Paid", "orderAmount": 5393.75, "details": { "street": "SS road", "postCOde": "440111" }, "subOrders": [{ "name": "sub Product1", "mrp": 12 }, { "name": "subProduct2", "mrp": 89 }] }] const isPrimitive = (x)=>x === null || typeof x !== "object" function sanitize(o, permissions, prefix='') { if (isPrimitive(o)) return o const sanitized = {} for (const[k,v] of Object.entries(o)) { const qk = `${prefix}${k}` if (permissions.some((p)=>p.match(new RegExp(`^${qk}`)))) { sanitized[k] = Array.isArray(v) ? sanitizeArray(v, permissions, `${qk}.`) : sanitize(v, permissions, `${qk}.`) } } return sanitized } const sanitizeArray = (arr,permissions,prefix='')=>arr.map((el)=>sanitize(el, permissions, prefix)) const permissions = ['logistics', 'paymentStatus', 'details.street', 'subOrders.name'] const sanitized = sanitizeArray(data, permissions) console.log(sanitized)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM