0

I have an array returnedDocs in code below (shortened via let returnedDocs = result.application.modules.module.moduleItem;) that I got as response from API, it structure is pretty complex. Some nested objects are arrays some values are placed few levels deep in the structure.

I use filter method to get only those elements that got specific value.

          let toFilterSix = returnedDocs.filter(
            o =>
              o.repeatableGroup.repeatableGroupItem.vocabularyReference
                .vocabularyReferenceItem.formattedValue._text === "Abdomen"
          );
          this.filterArray6 = toFilterSix;

Normally it works fine but in below example one of repeatableGroupItem is an array with two elements (image).

arrayInArray

I've got an error due to fact that there is unexpected array within filtered objects:

Results.vue?82a0:202 Uncaught (in promise) TypeError: Cannot read property 'vocabularyReferenceItem' of undefined
    at eval (Results.vue?82a0:202)
    at Array.filter (<anonymous>)
    at eval (Results.vue?82a0:201)

How can I avoid the error when do filter on other, non-array elements?

Here you can examine the data model, it's console.log'ed: https://lucid-villani-539a6f.netlify.com/results

  • please provide an example of your data model, and if possible try to rephrase and simplify your question a bit - as it stands it's a little difficult to interpreted. – zfrisch Sep 19 '19 at 20:21
  • You probably want to look at [Test for existence of nested JavaScript object key](https://stackoverflow.com/q/2631001/215552) to test for the existence of the property you're targeting before descending to it. – Heretic Monkey Sep 19 '19 at 20:24

2 Answers2

1

If you just want to ignore the arrays, you can simply test whether repeatableGroup has a vocabularyReferences property.

let toFilterSix = returnedDocs.filter(
  o =>
  o.repeatableGroup.repeatableGroupItem.vocabularyReference &&
  o.repeatableGroup.repeatableGroupItem.vocabularyReference.vocabularyReferenceItem.formattedValue._text === "Abdomen"
);

If you want to search the array as well, you can use an if statement to search that when it's an array.

let toFilterSix = returnedDocs.filter(
  o => {
    if (Array.isArray(o.repeatableGroup.repeatableGroupItem)) {
      return o.repeatableGroup.repeatableGroupItem.some(el => el.vocabularyReference.vocabularyReferenceItem.formattedValue._text === "Abdomen");
    } else {
      return o.repeatableGroup.repeatableGroupItem.vocabularyReference.vocabularyReferenceItem.formattedValue._text === "Abdomen";
    }
  });
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Great thanks! It saves the day (I used second snippet) and I have a starting point for some of my other bottlenecks with filtering and exceptions for non existing elements returned from API. – sebastian sledz Sep 19 '19 at 20:43
0

If you're trying to look for "Abdomen" regardless of whether it's a single object or an array of those objects, you could use [].concat(repeatableGroupItem). This allows you to safely assume you're dealing with an array instead of handling each case individually.

From there you could use .some() to determine if "Abdomen" exists within any of the items.

// This array contains 4 objects... 
//   1: repeatableGroupItem as single object, containing "Abdomen"
//   2: repeatableGroupItem as array of objects, containing "Abdomen"
//   3: repeatableGroupItem as single object, without "Abdomen"
//   4: repeatableGroupItem as array of objects, without "Abdomen"
const returnedDocs = [{ repeatableGroup: { repeatableGroupItem: { vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Abdomen" } } } } } }, { repeatableGroup: { repeatableGroupItem: [{ vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Abdomen" } } } }, { vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Abdomen" } } } } ] } }, { repeatableGroup: { repeatableGroupItem: { vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Not Abdomen" } } } } } }, { repeatableGroup: { repeatableGroupItem: [{ vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Not Abdomen" } } } }, { vocabularyReference: { vocabularyReferenceItem: { formattedValue: { _text: "Not Abdomen" } } } } ] } }];

const result = returnedDocs.filter(o => {
  const item = [].concat(o.repeatableGroup.repeatableGroupItem);
  return item.some(i => i.vocabularyReference.vocabularyReferenceItem.formattedValue._text === "Abdomen");
});

//Logs items 1 and 2
console.log(result);
Tyler Roper
  • 21,445
  • 6
  • 33
  • 56