如何遍历复杂的Json对象并在每个属性上执行等于某个值的操作

时间:2019-05-27 06:36:43

标签: javascript arrays node.js json object

我遇到了以下问题,

我需要遍历一个大的Json对象(子节点由数组,字符串和深度至少为4-5层的嵌套对象组成)。

在Json大文件的某些部分中,有一个特定的对象结构,它具有一个名为“ erpCode”的属性。我需要扫描Json并找到具有该属性的所有对象,使用该代码的值向其他API询问详细信息,并在获得详细信息后使用当前的“ erpCode”将其插入对象。

仅说明一下,在我的案例中,Json中的父节点属性名称始终等于与erpCode属性位于同一“级别”上的“ typeSysname”字段中的值。 一个简单的例子:

{
   "cars": [
    {
      "name": "X222",
      "carType": {
         "erpCode": "skoda",
         "value": null,
         "typeSysName": "carType"
       }
    }
    ],
    "model": {
       "year": 1999,
       "details": {
           "erpCode": "112"
           "value": null,
           "typeSysName": "details"
        } 
     } 
}

在此示例中,我需要找到2个属性,分别从其中获取skoda值和112个值,并从不同的API获取值和描述数据,并将其设置在正确位置的Json中。

P.S。有没有一个好的npm软件包可以帮助我解决这个问题?

编辑: 几个月前,我在C#中获得了一个解决方案,该解决方案在Json上以通用方式运行,并以通用方式处理结构的复杂性。 但是我现在需要将其转换为Javascript,我有点迷茫。

public static string TranslateDocErpCodes(string jsonString, string topRetailerSysName)
        {

            try
            {
                var doc = JObject.Parse(jsonString);
                var erpCodeList = doc.SelectTokens("$..erpCode").ToList();

                foreach (var erpCodeJToken in erpCodeList)
                {
                    var value = erpCodeJToken?.Value<string>();
                    var erpCodeParent = erpCodeJToken?.Parent.Parent;
                    var erpCodeProperty = erpCodeParent?.Path.Split(".").Last();

                    var result =
                        _dataService.GetLovFromErpCode(topRetailerSysName, erpCodeProperty, value);

                    if (result == null)//reset lov obj
                    {
                        if (erpCodeParent?.Parent is JProperty prop)
                            prop.Value = JObject.FromObject(new LovObject { ErpCode = value });
                    }
                    else//set lov obj
                    {
                        result.ErpCode = value;
                        if (erpCodeParent?.Parent is JProperty prop)
                            prop.Value = JObject.FromObject(result);
                    }

                }
                return JsonConvert.SerializeObject(doc);
            }
            catch (Exception e)
            {
                throw new Exception("ErpConvert.TranslateDocErpCodes() : " + e);
            }
        }

3 个答案:

答案 0 :(得分:1)

mb类似;

function processObject(jsonData) {
    for (prop in jsonData) {
        if (jsonData.hasOwnProperty(prop)) {
            // We get our prop
            if (prop === 'code') {
                let codeValue = jsonData[prop]
                doSomeAsync(codeValue)
                    .then(response => {
                        jsonData[prop] = response;
                    })
            }
            let curValue = jsonData[prop];
            if (Array.isArray(curValue)) {
                // Loop through the array, if array element is an object, call processObject recursively.
                processArray(curValue);
            } else if (typeof curValue === 'object') {
                processObject(curValue);
            }
        }
    }
}

答案 1 :(得分:0)

我以Aravindh的回答为出发点,设法找到了似乎完整的解决方案。 我将在这里分享,

async function convertErpCodes(jsonData, orgName, parentPropertyName){    
        for (let prop in jsonData) {
          if (jsonData.hasOwnProperty(prop)) {
              if (prop === 'erpCode') {
                  const erpCodeValue = jsonData[prop]
                  const req = {"query": {"erpCode": erpCodeValue, "orgName": orgName, "typeSysName": parentPropertyName}};
                  const result = await viewLookupErpService.findOne(req);
                  if(result)
                    return result; 
              }
              const curValue = jsonData[prop];
              if (Array.isArray(curValue)) {
                  for(let i in curValue){
                    const res = await convertErpCodes(curValue[i], orgName, prop);
                  }
              } else if (curValue && typeof curValue === 'object') {
                const response = await convertErpCodes(curValue, orgName, prop);
                if(response){
                    jsonData[prop] = response;
                }
              }
          }
      }
}

P.S。 仅当我从第三方API得到响应时才设置这些值(这是递归中结果和响应逻辑的原因。

答案 2 :(得分:0)

我会同时使用object-scanlodash.set

const objectScan = require('object-scan');
const set = require('lodash.set');

const stats = { "cars": [{ "name": "X222", "carType": { "erpCode": "skoda", "value": null, "typeSysName": "carType" } }], "model": { "year": 1999, "details": { "erpCode": "112", "value": null, "typeSysName": "details" } } };

const entries = objectScan(['**.erpCode'], { rtn: 'entry' })(stats);
console.log(entries);
// => [ [ [ 'model', 'details', 'erpCode' ], '112' ],
//   [ [ 'cars', 0, 'carType', 'erpCode' ], 'skoda' ] ]

// TODO: query external api here and place in entries
entries[0][1] = 'foo';
entries[1][1] = 'bar';

entries.forEach(([k, v]) => set(stats, k, v));
console.log(JSON.stringify(stats));
// => {"cars":[{"name":"X222","carType":{"erpCode":"bar","value":null,"typeSysName":"carType"}}],"model":{"year":1999,"details":{"erpCode":"foo","value":null,"typeSysName":"details"}}}