Home > Net >  Filter array of object inside array of object
Filter array of object inside array of object

Time:11-08

I am trying to filter this json.

here is the json

const json = {
  address: "fdqn",
  pDet: [
    {
      pNam: "pnam1",
      pMem: [
        {
          mIP: "1234",  // search this string '1234'
          gp: "gp1"
        }, {
          mIP: "567", 
          gp: "gp2"
        }, {
          mIP: "890", 
          gp: "gp3"
        }
      ]
    },
    {
      pNam: "pnam1",
      pMem: [
        {
          mIP: "4567", 
          gp: "gp5"
        }, {
          mIP: "5674", 
          gp: "gp7"
        }
      ]
    }
  ]
}

I need to filter with mIP = "1234" and the final output should be.

const json = {
    address: "fdqn",
    pDet: [
      {
        pNam: "pnam1",
        pMem: [
          {
            mIP: "1234", 
            gp: "gp1"
          }
        ]
      }
    ]
  }

i tried with filter and some but seems i need to iterate inside the filter. any input will be appreciated

CodePudding user response:

Utilizing flatMap to emulate the behavior of filter_map in other languages, we could achieve the result like this:

const json = {address:"fdqn",pDet:[{pNam:"pnam1",pMem:[{mIP:"1234",gp:"gp1"},{mIP:"567",gp:"gp2"},{mIP:"890",gp:"gp3"}]},{pNam:"pnam1",pMem:[{mIP:"4567",gp:"gp5"},{mIP:"5674",gp:"gp7"}]}]};

const search = "1234";

const result = {
    address: json.address,
    // check if there is any match in this pMem
    pDet: json.pDet.flatMap(({ pMem }) => pMem.some(({ mIP }) => mIP === search)
        ? [pMem.filter(({ mIP }) => mIP === search)] // if there is, return filtered array
        : [] // otherwise, return nothing
    ),
};

console.log(result);

CodePudding user response:

You could use array.reduce() and array.filter() like this.

const json = { address: "fdqn", pDet: [{ pNam: "pnam1", pMem: [{ mIP: "1234", gp: "gp1" }, { mIP: "567", gp: "gp2" }, { mIP: "890", gp: "gp3" }] }, { pNam: "pnam1", pMem: [{ mIP: "4567", gp: "gp5" }, { mIP: "5674", gp: "gp7" }] } ] }

const newJSON = {
    address: json.address,
    pDet: json.pDet.reduce((newArr, obj) => {
        const pMem = obj.pMem.filter(obj2 => obj2.mIP === '1234')
        if (pMem.length) newArr.push({
            pNam: obj.pNam,
            pMem
        })
        return newArr
    }, [])
}

console.log(newJSON)

In a function it could look like this:

const json = { address: "fdqn", pDet: [{ pNam: "pnam1", pMem: [{ mIP: "1234", gp: "gp1" }, { mIP: "567", gp: "gp2" }, { mIP: "890", gp: "gp3" }] }, { pNam: "pnam1", pMem: [{ mIP: "4567", gp: "gp5" }, { mIP: "5674", gp: "gp7" }] } ] }

function filterArray(jsonObj, searchStr) {
    return {
        address: json.address,
        pDet: json.pDet.reduce((newArr, obj) => {
            const pMem = obj.pMem.filter(obj2 => obj2.mIP === search)
            if (pMem.length) newArr.push({
                pNam: obj.pNam,
                pMem
            })
            return newArr
        }, [])
    }
}

const newJSON = filterArray(json, '1234')

console.log( newJSON )

CodePudding user response:

Similar to the technique in the answer from @caTS, although a little more generic, I used a filterMap. In my case, I grabbed a reusable function I have handy. It looks like this:

const filterMap = (f, m) => (xs) => xs .flatMap (x => f (x) ? [m (x)] : [])

const searchMIP = ({pDet, ...rest}, query) => ({
  ...rest,
  pDet: filterMap (
    ({pMem}) => pMem .some (({mIP}) => mIP == query),
    ({pMem, ...rest}) => ({...rest, pMem: pMem .filter (({mIP}) => mIP == query)})
  ) (pDet)
})

const obj = {address: "fdqn", pDet: [{pNam: "pnam1", pMem: [{mIP: "1234", gp: "gp1"}, {mIP: "567", gp: "gp2"}, {mIP: "890", gp: "gp3"}]}, {pNam: "pnam1", pMem: [{mIP: "4567", gp: "gp5"}, {mIP: "5674", gp: "gp7"}]}]}

console .log (searchMIP (obj, '1234'))

But I wasn't really happy with that, as one of the usual advantages of filterMap is that it only scans the list once. But here, we do it in the filter section, using some and again in the map section using filter.

So here's a slightly different approach, still using flatMap to do something similar, but filtering only once and using the length of the result to decide whether we're keeping the object at all:

const searchMIP = ({pDet, ...rest}, query) => ({
  ...rest,
  pDet: pDet .flatMap (
    ({pMem, kids = pMem .filter (({mIP}) => mIP == query), ...rest}) => kids .length ? [({
      ...rest, 
      pMem: pMem .filter (({mIP}) => mIP == query)
    })] : [] 
  )
})

const obj = {address: "fdqn", pDet: [{pNam: "pnam1", pMem: [{mIP: "1234", gp: "gp1"}, {mIP: "567", gp: "gp2"}, {mIP: "890", gp: "gp3"}]}, {pNam: "pnam1", pMem: [{mIP: "4567", gp: "gp5"}, {mIP: "5674", gp: "gp7"}]}]}

console .log (searchMIP (obj, '1234'))
.as-console-wrapper {max-height: 100% !important; top: 0}

This is more similar to the answer from user @Ludolfyn, but without the mutable accumulator, and again, slightly more generic.

  • Related