NodeJS: цикл по вложенному JSON и удаление элементов на основе условия - PullRequest
1 голос
/ 27 марта 2019

Допустим, у меня есть объект ниже:

{
"schema": [
{
  "field": "name",
  "type": "String",
  "enabled": true
},
{
  "field": "age",
  "type": "Int",
  "enabled": false
},
{
  "field": "modelObj",
  "type": "object",
  "enabled": true,
  "stuff": [
    {
      "name": "mod1",
      "type": "array",
      "enabled": true
    },
    {
      "name": "mod2",
      "type": "String",
      "enabled": false
    },
    {
     "name": "mod3",
      "type": "array",
      "enabled": true
    }
  ]
},
{
  "name": "modelArr",
  "type": "array",
  "enabled": false,
  "elements": {
    "elementsType": "String"
  }
},
{
  "name": "modelsNestedArr",
  "type": "array",
  "enabled": true,
  "elements": {
    "elementsType": "object"
  },
  "stuff": [
    {
      "name": "name",
      "type": "String",
      "enabled": true
    },
    {
      "name": "models",
      "type": "array",
      "enabled": false,
      "elements": {
        "elementsType": "String"
      }
    }
  ]
  }
  ]
  }

Я хочу рекурсивно пройти по этому объекту и, если установлено значение «enabled», удалить этот элемент.

Итак, ожидаемый результат:

[
{
  "field": "name",
  "type": "String",
  "enabled": true
},
{
  "field": "modelObj",
  "type": "object",
  "enabled": true,
  "stuff": [
    {
      "name": "mod1",
      "type": "array",
      "enabled": true
    },
    {
     "name": "mod3",
      "type": "array",
      "enabled": true
    }
  ]
},
{
  "name": "modelsNestedArr",
  "type": "array",
  "enabled": true,
  "elements": {
    "elementsType": "object"
  },
  "stuff": [
    {
      "name": "name",
      "type": "String",
      "enabled": true
    }
  ]
  }
 ]

Я написал код, приведенный ниже:

function r(a){
     for (i = a.length - 1; i >= 0; --i) {
        if(!a[i].enabled){
         a.splice(i,1)
        } else if (a[i].enabled){
            if(a[i].type == "object"){
              if(a[i]){
                a[i].stuff= r(a[i].stuff)
              }
        } else if (a[i].type == "array"){
            if(a[i].hasOwnProperty("elements") && a[i].elements.elementsType== "object"){
               a[i].stuff= r(a[i].stuff)
           }
        } 
      }
    }

    return a
    }

    var final = r(a.schema)
    console.log(JSON.stringify(final))

Но с этим я получаю следующий вывод:

Вывод с ошибкой:

[
{
"field": "name",
"type": "String",
"enabled": true
},
{
"field": "age",
"type": "Int",
"enabled": false
},
{
"field": "modelObj",
"type": "object",
"enabled": true,
"stuff": [
  {
    "name": "mod1",
    "type": "array",
    "enabled": true
  },
  {
    "name": "mod2",
    "type": "String",
    "enabled": false
  },
  {
    "name": "mod3",
    "type": "array",
    "enabled": true
  }
]
},
{
"name": "modelArr",
"type": "array",
"enabled": false,
"elements": {
  "elementsType": "String"
}
},
{
"name": "modelsNestedArr",
"type": "array",
"enabled": true,
"elements": {
  "elementsType": "object"
},
"stuff": [
  {
    "name": "name",
    "type": "String",
    "enabled": true
  }
]
}
]

Что именно я делаю не так?

Ответы [ 4 ]

2 голосов
/ 27 марта 2019

Рекурсивная функция с использованием .map () и .filter () облегчит вашу жизнь:

  function isEnabledRecursive(data){
    return data.filter(
      item=>item.enabled
    )
    .map(
      item=>item.stuff?Object.assign(item,{stuff:isEnabledRecursive(item.stuff)})
      :item
    );
  }
const dataWithFilteredSchema = Object.assign(data, {schema:isEnabledRecursive(data.schema)})

Это будет работать на любой глубине.

Предполагается, что все ваши массивы находятся в свойстве stuff.Если бы у вас были другие свойства с массивами объектов в них, вам пришлось бы циклически перебирать каждое свойство с чем-то вроде for(property of item), чтобы увидеть, есть ли в них массив.

Что касается того, почему ваш исходный код не является 'не работает, ничего в вашем другом, если заявления выполняются.Когда вы говорите a[i].type или a[i].dataType, оно не определено.Вы, вероятно, хотели сказать typeof a[i] === "object" и typeof a[i] === "array"

1 голос
/ 27 марта 2019

Судя по моим наблюдениям, либо ваш объект схемы несовместим, либо функция. Ваш объект схемы имеет ключи type и dataType . Я рассматриваю все это как type , и вот решение.

В вашей реализации сплайсинга массив был изменен в цикле и мог пропустить несколько индексов.

например. если массив был,

[
  {name: 'mod1', enabled: false},
  {name: 'mod2', enabled: true},
  {name: 'mod3', enabled: true}
]

После удаления индекса 0 длина массива становится 2 вместо 3. Следовательно, будет доступен один элемент меньше.

Следовательно, я включил еще один объект deleteIndices , чтобы пометить индексы для удаления после завершения цикла.

Кстати, вы всегда можете выбрать карту и фильтр , чтобы сделать этот путь проще.

function r(a) {
  let deleteIndices = {};
  for (let i = 0; i < a.length; i++) {
    if (!a[i].enabled) {
      deleteIndices[i] = true;
    } else {
      if (a[i].type == "object") {
        a[i].stuff = r(a[i].stuff)
      } else if (a[i].type == "array" && a[i].elements && a[i].elements.elementsType == "object") {
        a[i].stuff = r(a[i].stuff)
      }
    }
  }

  a = a.filter((e, index) => !deleteIndices[index])
  return a;
}

schema = r(schema)
0 голосов
/ 27 марта 2019

Самое простое и приятное решение, которое я мог придумать, и подойдет для любой глубины

function r(arr){
  let filtered =  arr.filter((obj)=>{
    return obj.enabled;
  });
  return filtered.map((obj)=>{
    if(obj.stuff)
      obj.stuff = r(obj.stuff)
    return obj
  })
}
result = r(a.schema)
console.log(JSON.stringify(result,null,2))
0 голосов
/ 27 марта 2019

Давайте назовем a ваш массив (object.schema), тогда результат можно получить так:

var result = a.filter(element => element.enabled).map(element => {
  if ((element.dataType == "object" || element.type == "array") && element.stuff && element.stuff.length > 0) {
    element.stuff = element.stuff.filter(st => st.enabled);
  }

  return element;
});

Будьте осторожны, иногда у вас есть dataType, а иногда у вас есть типыв качестве имени поля.

Вы должны использовать map и filter .Очень прост в написании и использовании.

Документы: карта , фильтр

...