У меня возникла следующая проблема,
Мне нужно перебрать большой объект 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);
}
}
может быть, что-то подобное может работать github.com/nahid/jsonq?
Неверный язык @SercanPaspal.
нет, в основном Json довольно сложный, это объект, и он содержит несколько массивов и объектов и простых строк, а внутри них он содержит больше объектов и массивов. На самом деле у меня есть рабочее решение C#, но теперь мне нужно «преобразовать» его в node.js, и у меня возникают проблемы с этим.
Какое у вас решение на С#? Можете ли вы отредактировать его в своем вопросе?
вы можете использовать jsonata.org, это легкий язык запросов и преобразований для данных JSON. это поможет тебе



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


мб что-то вроде;
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>Отказ от ответственности: я автор объектное сканирование
Должен ли второй объект находиться внутри массива
cars?