首页 > 解决方案 > 根据特定条件删除深度嵌套的 JavaScript 对象中的所有属性

问题描述

我有一个看起来像这样的对象(它是一个 Avro 模式):

{
  "type": "record",
  "namespace": "company.car.v1",
  "name": "CarV1",
  "fields": [
    {
      "name": "plateNumber",
      "type": "string"
    },
    {
      "name": "ownerId",
      "type": "string"
    },
    {
      "name" : "details", 
      "type" : {
            "type" : "record",
            "name" : "DetailsV1",
            "fields" : [
              {
                "name": "engine",
                "type": {
                  "type": "record",
                  "name": "EngineV1",
                  "fields": [
                    {
                      "name": "size",
                      "type": "int",
                      "default": 0
                    },
                    {
                      "name": "valvesCount",
                      "type": "int",
                      "default": 0
                    }
                  ]
                }
              },
              {
                "name" : "color", 
                "type" : "string", 
                "default" : "NONE"
              },
              {
                "name" : "rimSize",
                "type" : "int", 
                "default" : "NONE"
              }
             ]},
             "default" : {}
   },
    {
      "name": "isBrandNew",
      "type": "boolean"
    }
  ]
}

我的主要目标是拥有一个函数,该函数将此类对象作为输入并仅提取一些特定字段并生成此模式的子集。

所以一个看起来像这样的函数reduceSchema(avroSchema, [paths])

例如:

function reduceSchema(avroSchemaOnTop, ['ownerId', 'details.engine.size']

然后这将产生desired output

{
   "type":"record",
   "namespace":"company.car.v1",
   "name":"CarV1",
   "fields":[
      {
         "name":"ownerId",
         "type":"string"
      },
      {
         "name":"details",
         "type":{
            "type":"record",
            "name":"DetailsV1",
            "fields":[
               {
                  "name":"engine",
                  "type":{
                     "type":"record",
                     "name":"EngineV1",
                     "fields":[
                        {
                           "name":"size",
                           "type":"int",
                           "default":0
                        }
                     ]
                  }
               }
            ]
         },
         "default":{}
      }
   ]
}

目前,我可以将属性附加keepThisField到我想要保留的每个字段(及其父树),在本例中为 details.engine.size 和 ownerId

{
  "type": "record",
  "namespace": "company.car.v1",
  "name": "CarV1",
  "fields": [
    {
      "name": "plateNumber",
      "type": "string"
    },
    {
      "name": "ownerId",
      "type": "string",
      "keepThisField": "true"
    },
    {
      "name" : "details",
      "keepThisField": "true"
      "type" : {
            "type" : "record",
            "name" : "DetailsV1",
            "fields" : [
              {
                "name": "engine",
                "type": {
                  "type": "record",
                  "name": "EngineV1",
                  "fields": [
                    {
                      "name": "size",
                      "type": "int",
                      "default": 0,
                      "keepThisField": "true"
                    },
                    {
                      "name": "valvesCount",
                      "type": "int",
                      "default": 0
                    }
                  ]
                }
              },
              {
                "name" : "color", 
                "type" : "string", 
                "default" : "NONE"
              },
              {
                "name" : "rimSize",
                "type" : "int", 
                "default" : "NONE"
              }
             ]},
             "default" : {}
   },
    {
      "name": "isBrandNew",
      "type": "boolean"
    }
  ]
}

我现在需要的是一种机制,能够删除所有其他没有属性keepThisField的字段(以深度嵌套的方式),然后在keepThisField属性本身之后。所以我们只剩下desired output.

任何人都知道如何在 JavaScript 中以通用方式实现删除过程?


更新:

这是我用 flatMap 尝试过的:

function fn(o) {
  const hasMore = _.get(o, 'type.fields');

  if (o.keepThisField === true) {
    if (hasMore) {
      const retObj = {
        ...o,
        type: {
          ...o.type,
          fields: _.flatMap(o.type.fields, fn),
        }
      };

      _.unset(retObj, 'keepThisField');

      return retObj;
    }

    const cpO = o;
    _.unset(cpO, 'keepThisField');

    return ({
      ...cpO,
    });
  }

  return [];
}

parentSchema.fields = _.flatMap(parentSchema.fields, fn)

标签: javascriptarraysobjectjavascript-objects

解决方案


[回答我自己的问题]

去除部分过程的潜在解决方案。感谢@Kinglish 参考此 Stack Overflow 问题以使用 flatMap。

function fn(o) {
  const hasMore = _.get(o, 'type.fields');

  if (o.keepThisField === true) {
    if (hasMore) {
      const retObj = {
        ...o,
        type: {
          ...o.type,
          fields: _.flatMap(o.type.fields, fn),
        }
      };

      _.unset(retObj, 'keepThisField');

      return retObj;
    }

    const cpO = o;
    _.unset(cpO, 'keepThisField');

    return ({
      ...cpO,
    });
  }

  return [];
}

parentSchema.fields = _.flatMap(parentSchema.fields, fn)

推荐阅读