Фильтр Vue / Javascript в глубоком объекте внутри массива объектов

#javascript

#javascript

Вопрос:

Мне нужно глубоко отфильтровать объект категорий внутри массива, в массиве с несколькими объектами. При вызове API у меня будет этот массив объектов с вложенными категориями. Мне нужно отфильтровать каждый объект, если он содержит определенный идентификатор категории. Это JSON —

 items_loop: [
  {
    ID: 1,
    name: "Item A",
    taxonomy: {
      categories: [
        {
          name: "Book",
          parent: 12,
          taxonomy: "category",
        },
        {
          name: "Cover",
          parent: 4,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
  {
    ID: 2,
    name: "Item B",
    taxonomy: {
      categories: [
        {
          name: "Toys",
          parent: 16,
          taxonomy: "category",
        },
        {
          name: "Book",
          parent: 12,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
  {
    ID: 3,
    name: "Item C",
    taxonomy: {
      categories: [
        {
          name: "Ext",
          parent: 6,
          taxonomy: "category",
        },
        {
          name: "Cover",
          parent: 4,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
]
  

Я хочу создать новый массив с объектом, который содержит только «родительский»: 15, но как я могу глубоко отфильтровать этот объект 3? Я пытался с этим, но это не работает

 function findInObjArray(array, value) {
  var found = []

  // Helper to search obj for value
  function findInObj(obj, value) {
    return Object.values(obj).some((v) =>
      // If v is an object, call recursively
      typeof v == "object" amp;amp; v != "null"
        ? findInObj(v, value)
        : // If string, check if value is part of v
        typeof v == "string"
        ? v.indexOf(value) >= 0
        : // Check numbers, make NaN == NaN
        typeof v == "number"
        ? v === value || (isNaN(v) amp;amp; isNaN(value))
        : // Otherwise look for strict equality: null, undefined, function, boolean
          v === value
    )
  }

  array.forEach(function (obj) {
    if (findInObj(obj, value)) found.push(obj)
  })

  return found
}
  

Комментарии:

1. condition ? val1 : val2 : val3 недопустимый синтаксис.

Ответ №1:

Вы имеете в виду что-то вроде этого — фильтровать массивы, которые находятся внутри объектов, которые находятся в вашем основном массиве? Вы можете повторять свой массив объектов по своему усмотрению и выполнять фильтрацию в цикле. Или используйте map метод, как в примере ниже:

 const obj = [{
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [{
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [{
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
}];
  
// Map and filter nested content
const res = obj.map(a => {
  a.taxonomy.categories = a.taxonomy.categories.filter(x => x.parent === 15);
  return a;
});
  
// Log
console.log(res)  

Или, если вы имеете в виду, что хотите отфильтровать свой основной массив, чтобы он содержал только объект, который имеет вложенный массив с некоторым значением — тогда это небольшая модификация предыдущего кода

 const obj = [{
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [{
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [{
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
}];
  
// Map and filter nested content
const res = obj.filter(a => {
  if((a.taxonomy.categories.filter(x => x.parent === 6)).length > 0) return a;
});
  
// Log
console.log(res)  

Ответ №2:

Приведенный ниже код должен возвращать массив только из item объектов, в которых вложенный categories массив был отфильтрован на совпадения.

Обратите внимание, что:

  • Возвращаются только элементы, содержащие по крайней мере 1 соответствующую категорию (это означает, что если элемент не содержит никаких соответствующих категорий, он не будет присутствовать в выходных данных).
  • В выходных данных присутствуют только соответствующие категории.
  • Если categoryFilterFunc не возвращает совпадений по всем элементам и категориям, возвращаемое значение будет пустым массивом.

 const obj = {
  items_loop : [
    {
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [
          {
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },
          {
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },                                                                              
        ]
      }
    },
    {
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [
          {
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },
          {
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },                                                                              
        ]
      }
    },
    {
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [
          {
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },
          {
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },             
        ]
      }
    },                      
  ]
};

function filterCategories(someObject, categoryFilterFunc) {
  return someObject.items_loop.reduce((accum, item) => {
    const filtered = item.taxonomy.categories.filter(categoryFilterFunc);
    if (filtered.length > 0) {
      // Creating a deep copy will have some performance impact (depending on
      // how many items and nested categories you need to iterate over)
      // but seems advisable for nested objects. Up to you if you
      // want to keep it.
      const deepCopy = JSON.parse(JSON.stringify(item));
      deepCopy.taxonomy.categories = filtered;
      accum.push(deepCopy);
    }
    return accum;
  }, []);
}

const matchingItems = filterCategories(obj, categoryObj => 15 === categoryObj.parent);

console.log(matchingItems);  

Комментарии:

1. Спасибо, это работает, но в вызове Api у меня много объектов. Я предпочитаю использовать приведенный ниже метод map. Спасибо за помощь!