2

I have an array like this

var data = [
    {
        family: "Fam A",
        category: "Cat A",
        products: [
            {
                name: "Name A1",
                style: "Style A1"
            },
            {
                name: "Name A2",
                style: "Style A2"
            }
        ]
    },
    {
        family: "Fam B",
        category: "Cat B",
        products: [
            {
                name: "Name B1",
                style: "Style B1"
            },
            {
                name: "Name B2",
                style: "Style B2"
            }
        ]
    }
]; 

I want to change the inside objects like below

var data = [
    {family:"Fam A", category: "Cat A", name: "Name A1", style:"Style A1"},
    {family:"Fam A", category: "Cat A", name: "Name A2", style:"Style A2"},
    {family:"Fam B", category: "Cat B", name: "Name B1", style:"Style B1"},
    {family:"Fam B", category: "Cat B", name: "Name B2", style:"Style B2"}
]  

I've tried using map and forEach that I found in other posts but haven't gotten anything to work.

var flattened = data.products.map(x => Object.assign(x, { productDetails: data.products }))

function getList(data, arrayKey, arrayName) {
    data[arrayKey].forEach(function(element) {
        element[arrayName] = data[arrayName];
    });
    return data[arrayKey];
}

The ideal solution would be able to handle dynamic no of nestings but not necessary to move on.

Thank you in advance for helping a newer dev!

2
  • Not supported in IE, but this javascript array method might get you partway there: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Mar 23, 2020 at 21:21
  • @brettB, do you still want "The ideal solution would be able to handle dynamic no of nestings"? If so check out my 2 recursive options. Commented Mar 24, 2020 at 20:34

3 Answers 3

4

You could take Array#flatMap with a nested mapping.

var data = [{ family: "Fam A", category: "Cat A", products: [{ name: "Name A1", style: "Style A1" }, { name: "Name A2", style: "Style A2" }] }, { family: "Fam B", category: "Cat B", products: [{ name: "Name B1", style: "Style B1" }, { name: "Name B2", style: "Style B2" }] }],
    flat = data.flatMap(({ products, ...o }) => products.map(p => ({ ...o, ...p })));

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

Sign up to request clarification or add additional context in comments.

5 Comments

I was hoping you were not online :(
@GuerricP, why ...?
I can't even try an answer before you post a beautiful one :p
Exactly what I'm looking for and clean to boot, thank you! Will accept when the timer allows.
Very nice clean solution. I also created a general (recursive) solution, below: stackoverflow.com/a/60822386/9792594
1

I can offer the general (recursive) solution:

var data = [
    {
        family: "Fam A",
        category: "Cat A",
        products: {
            somekey: 'someval',
            items : {
                type: 'A type',
                list: [{name: "Name A1", style: "Style A1"},
                      {name: "Name A2", style: "Style A2"}]
            }
        }
    },
    {
        family: "Fam B",
        category: "Cat B",
        products: {
            somekey: 'someval',
            items :[{name: "Name B1", style: "Style B1"},
                   {name: "Name B2", style: "Style B2"}]
        }
    }
]; 

const output = data.reduce((aggArr, child) => {   
  function recursiveFlat(currChild, currParent){
    currParent = currParent || {};
    return Object.entries(currChild).reduce((aggChildArr,[key,val]) => {
      let tempObj = {...currParent, ...currChild}
      if (val instanceof Array){
        delete tempObj[key];
        val.forEach(item => {
          aggChildArr.push({...tempObj,...item});
        })
      }else if(val instanceof Object){
        delete tempObj[key];
        aggChildArr = [...aggChildArr, ...recursiveFlat(val, tempObj)];
      }
      return aggChildArr;
    },[])
  }
  const flatArr = recursiveFlat(child);
  flatArr.forEach(item => aggArr.push(item));
  return aggArr;
},[])

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

update, trying to take the beautiful .flatMap() solution and make it generic & recursive:

const data = [{ family: "Fam A", category: "Cat A", items: { types: {type: 'A1-2', products: [{ name: "Name A1", style: "Style A1" }, { name: "Name A2", style: "Style A2" }]}, somekey: 'example' } }, { family: "Fam B", category: "Cat B", products: [{ name: "Name B1", style: "Style B1" }, { name: "Name B2", style: "Style B2" }] }];
    
function flatten(data){
  const flat = data.flatMap((obj) => {
    function innerFlatten(obj, parentObj){
      parentObj = parentObj || {};
      for (key in obj){
        if (obj[key] instanceof Array){
          const tempArr = obj[key];
          delete obj[key];
          return tempArr.map(p => ({...parentObj, ...obj, ...p }) ) 
        }else if (obj[key] instanceof Object){
          const tempObj = obj[key];
          delete obj[key];
          return innerFlatten(tempObj, {...parentObj, ...obj});
        }  
      }      
    }
    return innerFlatten(obj);    
  });
  return flat;
}

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

5 Comments

what's the benefit of using this instead of a one-liner like in the accepted answer? ;)
@GuerricP - the question said "ideal solution would be able to handle dynamic no of nestings" - my solution is recursive and dynamic to any depth. Also dynamic to any array, must not be named "products"
For the specific solution, I would use the one-liner, it's much more elegant. But if the OP really wants a more general solution, then we need to handle the depth and array name differently.
@AlexL I agree one-liner for my specific use case but this will likely come in handy sooner than later thank yoU!
Great to hear. My pleasure.
0

You can use reduce, faster and better.

var data = [{"family":"Fam A","category":"Cat A","products":[{"name":"Name A1","style":"Style A1"},{"name":"Name A2","style":"Style A2"}]},{"family":"Fam B","category":"Cat B","products":[{"name":"Name B1","style":"Style B1"},{"name":"Name B2","style":"Style B2"}]}];
const result = data.reduce(
  (map, { products, ...rest }) =>
    map.concat(products.map(product => ({ ...rest, ...product }))),
  []
);

console.log(result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.