Как перебирать сложный объект Json и что-то делать с каждым свойством, равным определенному значению

У меня возникла следующая проблема,

Мне нужно перебрать большой объект Json (дочерние узлы состоят из массивов, строк и объектов с глубиной не менее 4-5 слоев с точки зрения вложенных свойств).

В некоторых частях большого файла Json есть определенная структура объекта, у него есть свойство с именем «erpCode». Мне нужно отсканировать Json и найти все объекты с этим свойством, взять значение, использовать этот код, чтобы запросить подробности у другого API, и как только я получу подробности, вставить их в объект с текущим «erpCode».

Просто чтобы уточнить, в моем случае имя свойства родительского узла в Json всегда равно значению в поле «typeSysname», которое находится на том же «уровне», что и свойство erpCode. Простой пример:

{
   "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);
            }
        }

Должен ли второй объект находиться внутри массива cars?

Jack Bashford 27.05.2019 08:41

может быть, что-то подобное может работать github.com/nahid/jsonq?

Sercan Paspal 27.05.2019 08:43

Неверный язык @SercanPaspal.

Jack Bashford 27.05.2019 08:44

нет, в основном Json довольно сложный, это объект, и он содержит несколько массивов и объектов и простых строк, а внутри них он содержит больше объектов и массивов. На самом деле у меня есть рабочее решение C#, но теперь мне нужно «преобразовать» его в node.js, и у меня возникают проблемы с этим.

Ivgi 27.05.2019 08:45

Какое у вас решение на С#? Можете ли вы отредактировать его в своем вопросе?

Jack Bashford 27.05.2019 08:46

вы можете использовать jsonata.org, это легкий язык запросов и преобразований для данных JSON. это поможет тебе

eagle 27.05.2019 08:50
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
6
555
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

мб что-то вроде;

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);
            }
        }
    }
}
Ответ принят как подходящий

Я взял ответ Аравинда в качестве отправной точки и сумел найти то, что кажется полным решением. Я поделюсь этим здесь,

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 (это причина логики результата и ответа в рекурсии.

Я бы использовал комбинацию объектное сканирование и lodash.set.

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

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.info(entries);
// => [ [ [ 'model', 'details', 'erpCode' ], '112' ], [ [ 'cars', 0, 'carType', 'erpCode' ], 'skoda' ] ]

// where you would query the external api and place results in entries
entries[0][1] = 'foo';
entries[1][1] = 'bar';

entries.forEach(([k, v]) => lodash.set(stats, k, v));
console.info(stats);
// => { cars: [ { name: 'X222', carType: { erpCode: 'bar', value: null, typeSysName: 'carType' } } ], model: { year: 1999, details: { erpCode: 'foo', value: null, typeSysName: 'details' } } }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src = "https://bundle.run/[email protected]"></script>
<script src = "https://bundle.run/[email protected]"></script>

Отказ от ответственности: я автор объектное сканирование

Другие вопросы по теме