Home > Back-end >  Object nested reduce or map into one object
Object nested reduce or map into one object

Time:09-17

I have an object like this that I need to flatten meaning the shellfish species would just say 'species': '' and would not be nested?

batches:
    [
       {
          "name":"Batch1",
          "description":"seed",
          "age":2,
          "quantity":1000,
          "source":"Hatchery",
          "hatchery":"robs hatchery",
          "location":"dingle",
          "shellfish":{
             "species":"pacific gigas"
          },
          "stock_type":"seeds"
       },
       {
          "name":"Batch2",
          "description":"Batch2",
          "age":20,
          "quantity":15700,
          "source":"aka",
          "hatchery":"aka",
          "location":"dingle",
          "shellfish":{
             "species":"pacific gigas"
          },
          "stock_type":"mature"
       },
       {
          "name":"5555",
          "description":"45",
          "age":1,
          "quantity":134,
          "source":"fhh",
          "hatchery":"hfhj",
          "location":"garden",
          "shellfish":{
             "species":"pacific gigas"
          },
          "stock_type":"seeds"
       }
    ]

I had a qs yesterday about how to flatten another JSON and I had the shellfish nest to have 'name' and stock type was also nested with 'name' and I got an answer on how to flatten all objects with sub prop 'name', after using that I come out with this JSON result and need to do it again to flatten this nested shellfish object

the JSON result above comes after this function is called

   async getBatches() {
          try {
            let res = await farmStockService.getAllBatches();
    
            
    
            const result = res.data.data.map((element) => {
              const keysWithNameProp = Object.keys(element).filter(key => element[key].name !== undefined);
              const copyOfElement = {...element};
              keysWithNameProp.forEach(prop => {
                copyOfElement[prop] = element[prop].name;
              })
              return copyOfElement;
            });
    
           
    
            this.batches = result;
    
          } catch (e) {
            console.error(e);
          }
        },

maybe there is a way to tweak the function so it flattens anything with sub prop 'name' and also 'array'? I tried playing with it but crashed every time, its also in a vuejs component

the table looks like this now:

enter image description here

Thanks so much for any response!

Last qs: enter image description here

CodePudding user response:

You may use ... spread operator.

If the key is not dynamic, you can use solution1 below.

const response = { data: [ { name: "Batch1", description: "seed", age: 2, quantity: 1000, source: "Hatchery", hatchery: "robs hatchery", location: "dingle", shellfish: { species: "oyster", }, grade_list: { name: "Grade0", }, stock_type: { name: "seeds", }, }, { name: "Batch2", description: "Batch2", age: 20, quantity: 15700, source: "aka", hatchery: "aka", location: "dingle", shellfish: { species: "oyster", }, grade_list: { name: "Grade1", }, stock_type: { name: "mature", }, }, { name: "5555", description: "45", age: 1, quantity: 134, source: "fhh", hatchery: "hfhj", location: "garden", shellfish: { species: "oyster", }, grade_list: { name: "Grade0", }, stock_type: { name: "seeds", }, }, ], };

const result1 = response.data.map(item => ({
  ...item,
  shellfish: item.shellfish.species,
  grade_list: item.grade_list.name,
  stock_type: item.stock_type.name,
}));

console.log({result1});

If the key is dynamic, you can use solution2 below.

const response = { data: [ { name: "Batch1", description: "seed", age: 2, quantity: 1000, source: "Hatchery", hatchery: "robs hatchery", location: "dingle", shellfish: { species: "oyster", }, grade_list: { name: "Grade0", }, stock_type: { name: "seeds", }, }, { name: "Batch2", description: "Batch2", age: 20, quantity: 15700, source: "aka", hatchery: "aka", location: "dingle", shellfish: { species: "oyster", }, grade_list: { name: "Grade1", }, stock_type: { name: "mature", }, }, { name: "5555", description: "45", age: 1, quantity: 134, source: "fhh", hatchery: "hfhj", location: "garden", shellfish: { species: "oyster", }, grade_list: { name: "Grade0", }, stock_type: { name: "seeds", }, }, ], };

function isObject(obj) {
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
}

const result2 = response.data.map(item => {
  const keys = Object.keys(item);

  let flattenObj = {};
  for (const key of keys) {
    const value = item[key];
    if (isObject(value)) {
      flattenObj = { ...flattenObj, [key]: value[Object.keys(value)[0]] };
    }
  }
  return { ...item, ...flattenObj };
});

console.log(result2);

CodePudding user response:

You can define a helper function resolveNestedProps() which accepts an object and an array of properties to look for. If any of them are found it returns the value, otherwise it returns the obj. Note that this will return the first property that matches, so if any of your objects have a name and species whichever is matched first will be returned.

Here iterating over the Object.entries() of each element and returning a new object using Object.fromEntries()

const res = { data: { data: [ { name: 'Batch1', description: 'seed', age: 2, quantity: 1000, source: 'Hatchery', hatchery: { name: 'robs hatchery' }, location: { name: 'dingle' }, shellfish: { species: 'pacific gigas' }, stock_type: 'seeds', }, { name: 'Batch2', description: 'Batch2', age: 20, quantity: 15700, source: 'aka', hatchery: { name: 'aka' }, location: { name: 'dingle' }, shellfish: { species: 'pacific gigas' }, stock_type: 'mature', }, { name: '5555', description: '45', age: 1, quantity: 134, source: 'fhh', hatchery: { name: 'hfhj' }, location: { name: 'garden' }, shellfish: { species: 'pacific gigas' }, stock_type: 'seeds', }, ], }, };

const resolveNestedProps = (obj, props) => {
  for (const key of props) {
    if (obj[key] !== undefined) {
      return obj[key];
    }
  }

  return obj;
};

const nestedProps = ['name', 'species']; // define properties to look for
const result = res.data.data.map((element) =>
  Object.fromEntries(
    Object.entries(element).map(([k, v]) => {
      if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
        v = resolveNestedProps(v, nestedProps);
      }

      return [k, v];
    })
  )
);

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

  • Related