Home > database >  How to filter on a nested object property in JavaScript?
How to filter on a nested object property in JavaScript?

Time:12-24

The following returns all arrProps that have a matching arrValues value:

const arr = [
{ arrProps: [{name: '1', prop2: 'aaa'}], arrValues: ['apple', 'orange'] },
{ arrProps: [{name: '2', prop2: 'bbb'}], arrValues: ['taco', 'orange' ] },
{ arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: ['fish', 'apple', 'orange'] }
];

const result = arr
  .flatMap(({ arrValues }) => arrValues )  // all values
  .filter((value, index, coll) => coll.indexOf(value) === index) //unique values
  .reduce((acc, value) => {
      const parentProp = arr      // name, prop2, arrValues
          .filter((obj) => obj.arrValues.includes(value))
          .map((obj) => obj.arrProps[0].name);
          //.map((obj) => [{ source: obj.arrProps[0].name, value: obj.arrValues[0], sourceID: null}]);

      acc[value] = (acc[value] ? [...acc[value], parentProp] : [parentProp])
      .join(',');
      acc[value] = parentProp
      
    return acc;
}, {})

console.log(result);
console.table(result);

enter image description here

I need to add additional properties to arrValues, thereby using objects rather than values:

const arr = [
    { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ symbol: 'apple', id: '1.apple' }, {symbol: 'orange', id: '1.orange'}] },
    { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ symbol: 'fish', id: '2.fish' }, { symbol: 'pizza', id: '2.pizza' }, { symbol: 'red', id: '2.red' }] },
    { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ symbol: 'grape', id: '3.grape'}, { symbol: 'apple', id: '3.apple' }] },
];

From simply 'apple', I need to add some additional uniquely identifying values, i.e. { symbol: 'apple', id: '1.apple' }

I'm sure it's in here:

aMap.filter((value, index, coll) => coll.indexOf(value) === index) // <--- filter issue

Which is returning the object (previous data model, just the value 'apple', 'orange'...):

Array(7) [Object, Object, Object, Object, Object, Object, Object]
    [[Prototype]]: Array(0)
    length: 7
    0: Object {symbol: "apple", id: "1.apple"}
    1: Object {symbol: "orange", id: "1.orange"}
    2: Object {symbol: "fish", id: "2.fish"}
    3: Object {symbol: "pizza", id: "2.pizza"}
    4: Object {symbol: "red", id: "2.red"}
    5: Object {symbol: "grape", id: "3.grape"}
    6: Object {symbol: "apple", id: "3.apple"}
    __proto__: Array(0)

I'm having a heck of a time trying to filter on arrValues[0].symbol. I then need to append arrValues[0].id to the results. I figure createing a new object with arrProps and the unique ID would be best.

So in the case of apple, the first column should render {parent: arrProps[0], id: arrValues[0].id}, etc.

--- UPDATE ---

Rather than just showing the name of arrPorps[0].name, I need an object returned, as per the last line above (a change from the original question).

I had thought about finding some way to append arrProps to the output but got stuck there. Since I can hydrate the data model, I added some additional identifying properties to arrValues[] (wait, does this and arrProps[] really need to be an array, it's just an object - refactor?):

const arr = [
    { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ exchange: '1', symbol: 'apple', id: '1.apple' }, {exchange: '1', symbol: 'orange', id: '1.orange' }] },
    { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ exchange: '2', symbol: 'fish', id: '2.fish' }, { exchange: '2', symbol: 'pizza', id: '2.pizza' }, { exchange: '2', symbol: 'red', id: '2.red' }] },
    { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ exchange: '3', symbol: 'grape', id: '3.grape' }, { exchange: '3', symbol: 'apple', id: '3.apple' }] },
];

Then changed the output, creating an output object,

From: .map(({ arrProps }) => arrProps[0].name)

To: .map(({ arrValues }) => [{ exchange: arrValues[0].exchange, symbol: arrValues[0].symbol, id: arrValues[0].id }]);

Whole updated code:

    const arr = [
        { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ exchange: '1', symbol: 'apple', id: '1.apple' }, {exchange: '1', symbol: 'orange', id: '1.orange' }] },
        { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ exchange: '2', symbol: 'fish', id: '2.fish' }, { exchange: '2', symbol: 'pizza', id: '2.pizza' }, { exchange: '2', symbol: 'red', id: '2.red' }] },
        { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ exchange: '3', symbol: 'grape', id: '3.grape' }, { exchange: '3', symbol: 'apple', id: '3.apple' }] },
    ];
    
    const objectValues = arr.flatMap(({ arrValues }) => arrValues);  // not necessary if we refactor, removing these arrays?
    const values = objectValues.map(({ symbol }) => symbol);
    const uniqueValues = [...new Set(values)];
    const result = uniqueValues.reduce((acc, value) => {
        acc[value] = arr
            .filter(({ arrValues }) => {
                const symbols = arrValues.map(({ symbol }) => symbol)
                return symbols.includes(value);
            })
            //.map(({ arrProps }) => arrProps[0].name)
            .map(({ arrValues }) => [{ exchange: arrValues[0].exchange, symbol: arrValues[0].symbol, id: arrValues[0].id }]);
            //.join(',');
        return acc;
    }, {});
    
    console.log("RAW:"   JSON.stringify(result));
    
    console.log(result);
    console.table(result);
    
    Object.entries(result).forEach(([k, v]) => {
        console.log(`      ----] The value '${k}' exists in:`);
        console.table(JSON.stringify(v));
        //console.log("The pair: ", k)
        ////console.log("The value: ", v)
        v.forEach(_pool => console.log(`
            Exchange: ${_pool[0].exchange}
            symbol: ${_pool[0].symbol}
            ID: ${_pool[0].id}
        `));
    })

Two problems:

  1. I think the arrays are not necessary in the data model
  2. The output data is wrong.
{
   "apple":[
      [
         {
            "exchange":"1",
            "symbol":"apple",
            "id":"1.apple"
         }
      ],
      [
         {
            "exchange":"3",
            "symbol":"grape",   // should be "apple"
            "id":"3.grape"      // should be "3.apple"
         }
      ]
   ],
   "orange":[
      [
         {
            "exchange":"1",
            "symbol":"apple",   // should be "orange"
            "id":"1.apple"      // should be "1.orange"
         }
      ]
   ],
   "fish":[
      [
         {
            "exchange":"2",
            "symbol":"fish",
            "id":"2.fish"
         }
      ]
   ],
   "pizza":[
      [
         {
            "exchange":"2",
            "symbol":"fish",   // should be pizza
            "id":"2.fish"      // should be 2.pizza
         }
      ]
   ],
   "red":[
      [
         {
            "exchange":"2",
            "symbol":"fish",   // should be "red"
            "id":"2.fish"      // should be "2.red"
         }
      ]
   ],
   "grape":[
      [
         {
            "exchange":"3",
            "symbol":"grape",
            "id":"3.grape"
         }
      ]
   ]
}

CodePudding user response:

After several approaches, I changed solution. In my opinion, it is now simpler and more versatile.

const arr = [
    { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ symbol: 'apple', id: '1.apple' }, {symbol: 'orange', id: '1.orange'}] },
    { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ symbol: 'fish', id: '2.fish' }, { symbol: 'pizza', id: '2.pizza' }, { symbol: 'red', id: '2.red' }] },
    { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ symbol: 'grape', id: '3.grape'}, { symbol: 'apple', id: '3.apple' }] },
];

const result = arr.reduce((acc, { arrProps: [{ name }], arrValues }) => {
    arrValues.map(({ symbol }) => symbol)
    .forEach((value) => {
        acc[value] = acc[value] ? `${acc[value]},${name}`: name;
    });
    return acc;
}, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

If we consider the previous approach with the filter, the solution could be as follows:

const arr = [
    { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ symbol: 'apple', id: '1.apple' }, {symbol: 'orange', id: '1.orange'}] },
    { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ symbol: 'fish', id: '2.fish' }, { symbol: 'pizza', id: '2.pizza' }, { symbol: 'red', id: '2.red' }] },
    { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ symbol: 'grape', id: '3.grape'}, { symbol: 'apple', id: '3.apple' }] },
];

const objectValues = arr.flatMap(({ arrValues }) => arrValues);
const values = objectValues.map(({ symbol }) => symbol);
const uniqueValues = [...new Set(values)];
const result = uniqueValues.reduce((acc, value) => {
  acc[value] = arr
    .filter(({ arrValues }) => {
      const symbols = arrValues.map(({ symbol }) => symbol)
      return symbols.includes(value);
    })
    .map(({ arrProps }) => arrProps[0].name)
    .join(',');
  return acc;
}, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

---UPDATE---

const arr = [
        { arrProps: [{ name: '1', prop2: 'aaa' }], arrValues: [{ exchange: '1', symbol: 'apple', id: '1.apple' }, {exchange: '1', symbol: 'orange', id: '1.orange' }] },
        { arrProps: [{ name: '2', prop2: 'bbb' }], arrValues: [{ exchange: '2', symbol: 'fish', id: '2.fish' }, { exchange: '2', symbol: 'pizza', id: '2.pizza' }, { exchange: '2', symbol: 'red', id: '2.red' }] },
        { arrProps: [{ name: '3', prop2: 'ccc' }], arrValues: [{ exchange: '3', symbol: 'grape', id: '3.grape' }, { exchange: '3', symbol: 'apple', id: '3.apple' }] },
    ];
    
    
const result = arr.reduce((acc, { arrValues }) => {
    arrValues.forEach((value) => {
        acc[value.symbol] = acc[value.symbol] 
          ? [...acc[value.symbol], value] 
          : [value]; 
    });
    return acc;
}, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related