Home > Net >  Search multiple elements by key inside multiple json structures
Search multiple elements by key inside multiple json structures

Time:10-13

I need to get the values of all the the arrays matching the items key. I'm making a script in Javascript that needs to read the objects inside multiple items arrays in multiple json files, but each json has a different structure. Example:

file1.json:

{
   "name":"First file",
   "randomName3874":{
      "items":[
         {
            "name":"item1"
         }
      ]
   },
   "items":[
      {
         "name":"randomItem2"
      }
   ]
}

file2.json

{
   "name":"Another file",
   "randomName00000":{
      "nestedItems":{
         "items":[
            {
               "name":"item87"
            }
         ]
      }
   },
   "stuff":{
      "items":[
         {
            "name":"randomItem35"
         }
      ]
   }
}

Desired result:

{
   "data":[
      {
         "items":[
            {
               "name":"item1"
            }
         ]
      },
      {
         "items":[
            {
               "name":"randomItem2"
            }
         ]
      },
      {
         "items":[
            {
               "name":"item87"
            }
         ]
      },
      {
         "items":[
            {
               "name":"randomItem35"
            }
         ]
      }
   ]
}

In both files I want to extract the arrays that have the key items. In the examples above the script should find 4 arrays. As you can see in both files each array is nested differently. How can I make this using Javascript?

CodePudding user response:

This will do it:

function omit(key, obj) {
  const { [key]: omitted, ...rest } = obj;
  return rest;
}

function getItems(obj) {
  return (typeof obj === 'object'
    ? 'items' in obj
      ? [{ items: obj.items }].concat(getItems(omit('items', obj)))
      : Object.values(obj).map(v => getItems(v))
    : []
  ).flat()
}
console.log({
  data: [file1, file2].map(o => getItems(o)).flat()
})

See it working:

Let's take it a step further and make it generic (work with an array of objects and extract any key) and provide it as a function, which you can use in other projects, as well:

function extractKey(objects, key) {
  const omit = (key, obj) => {
    const { [key]: omitted, ...rest } = obj;
    return rest;
  }

  const getValues = (obj) => (typeof obj === 'object'
    ? key in obj
      ? [{ [key]: obj[key] }].concat(getValues(omit(key, obj)))
      : Object.values(obj).map(o => getValues(o))
    : []
  ).flat();
  
  return objects.map(o => getValues(o)).flat()
}

// use: 
extractKey([file1, file2], 'items');

See it working:

CodePudding user response:

Looping over like a tree-nested loop should do it.

let file1 = {
    "name": "First file",
    "randomName3874": {
        "items": [
            {
                "name": "item1"
            }
        ]
    },
    "items": [
        {
            "name": "randomItem2"
        }
    ]
}

let file2 = {
    "name": "Another file",
    "randomName00000": {
        "nestedItems": {
            "items": [
                {
                    "name": "item87"
                }
            ]
        }
    },
    "stuff": {
        "items": [
            {
                "name": "randomItem35"
            }
        ]
    }
}

let itemsValues = [];
let desiredKey = 'items'

let loop = (value) => {
    if (Array.isArray(value)) { 
        value.forEach(loop);
    } else if (typeof value === 'object' && value !== null) {
        Object.entries(value).forEach(([key, val]) => (key === desiredKey) ? itemsValues.push({ [desiredKey]:  val }) : loop(val));
    }
}

loop(file1);
loop(file2);

console.log(itemsValues);

CodePudding user response:

This should work:

function getIdInObjects(id, objects, output = { data: [] }) {
  if (id in objects) output.data.push({[id]: objects[id]});

  for (const key in objects) {
    if (typeof(objects[key]) === 'object') getIdInObjects(id, objects[key], output);
  }
  return output;                                                                                                                                                                                                                         
}
console.log('items', [object1, object2])
  • Related