Home > Back-end >  How to flatten the nested array of of objects and duplicate the parent
How to flatten the nested array of of objects and duplicate the parent

Time:04-17

I have an array of objects that has one of the properties("attributes") as array of objects.

var products = [
    {
        "productId": "1",
        "attributes": [
            {
                "variant":"red",
                "price": "134.00"
            }
        ]
    },
    {
        "productId": "2",
        "attributes": [
            {
                "variant": "green",
                "value": "3400.00"
            },
            {
                "variant": "pink",
                "price": "342.00"
            }
        ]
    }
]

I want the nested array of objects to be flattened and copied onto parent but the parent object needs to be duplicated for each of the nested object. (Not sure if I have explained it correctly).

The converted array of objects should be:

var transformedProducts = [
    {
        "productId": "1",
        "variant":"red",
        "price": "134.00"
    },
    {
        "productId": "2",
        "variant": "green",
        "value": "3400.00"
    },
    {
        "productId": "2",
        "variant": "pink",
        "price": "342.00"
    }
]

I can map over the outer array and then again map over the inner array, and in the inner most map, construct a new object.
Is there a better or more functional approach to this?

CodePudding user response:

You can use Array.flatMap() to iterate the objects, and then iterate the attributes with Array.map(), and combine with the rest of the object. The Array.flatMap() would also flatten the array of arrays to a single array.

const fn = arr => arr.flatMap(({ attributes, ...rest }) => 
  attributes.map(o => ({
    ...rest,
    ...o
  }))
)

const products = [{"productId":"1","attributes":[{"variant":"red","price":"134.00"}]},{"productId":"2","attributes":[{"variant":"green","value":"3400.00"},{"variant":"pink","price":"342.00"}]}]

const result = fn(products)

console.log(result)

With Ramda, you can iterate and flatten the array using R.chain. To get an array of attributes combined with their parents, you can use the R.ap as combinator of two functions:

  1. Extracts the attributes array, and then applies it to the 2nd function.
  2. Gets the rest of the object (without the attributes), and creates a mapping function that merges it to the iterated objects.

const { chain, ap, pipe, prop, applyTo, omit, mergeRight, map } = R

const fn = chain(ap(
  pipe(prop('attributes'), applyTo),
  pipe(omit(['attributes']), mergeRight, map)
))

const products = [{"productId":"1","attributes":[{"variant":"red","price":"134.00"}]},{"productId":"2","attributes":[{"variant":"green","value":"3400.00"},{"variant":"pink","price":"342.00"}]}]

const result = fn(products)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

CodePudding user response:

This code should work for you:

const transformedProducts = [];

products.forEach((product) => {
    product.attributes.forEach((attribute) => {
        transformedProducts.push({
            productId: product.productId,
            ...attribute,
        });
    });
});

CodePudding user response:

You can use Array#map and Array#flat as follows:

const products = [ { "productId": "1", "attributes": [ { "variant":"red", "price": "134.00" } ] }, { "productId": "2", "attributes": [ { "variant": "green", "value": "3400.00" }, { "variant": "pink", "price": "342.00" } ] } ];

const output = products.map(({productId,attributes}) => 
    attributes.map(({variant,price}) => ({productId,variant,price}))
)
.flat();

console.log( output );

Or to only name attributes, in case there are other properties:

const products = [ { "productId": "1", "attributes": [ { "variant":"red", "price": "134.00" } ] }, { "productId": "2", "attributes": [ { "variant": "green", "value": "3400.00" }, { "variant": "pink", "price": "342.00" } ] } ];

const output = products.map(({attributes,...rest}) => 
    attributes.map(attribute => ({...rest,...attribute}))
)
.flat();

console.log( output );

  • Related