-1

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?

texpert
  • 185
  • 1
  • 3
  • 14

4 Answers4

6

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>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
3

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 );
PeterKA
  • 24,158
  • 5
  • 26
  • 48
0

This code should work for you:

const transformedProducts = [];

products.forEach((product) => {
    product.attributes.forEach((attribute) => {
        transformedProducts.push({
            productId: product.productId,
            ...attribute,
        });
    });
});
zielvna
  • 169
  • 5
0

In my case my array is having objects with in objects there are child array. I wanted a single array with all child objects

So I used this function to get all objects in a single array

  let array = [
      {
        id: 1,
        title: 't1',
        sort_order: 200,
        childs: [
          {
            id: 2,
            title: 't2',
            sort_order: 200,
            childs: [],
          },
          {
            id: 3,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
          {
            id: 4,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
          {
            id: 5,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
          {
            id: 6,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
        ],
      },
      {
        id: 7,
        title: 'راهنما',
        sort_order: 'mytitle',
        childs: [
          {
            id: 8,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
          {
            id: 9,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
          {
            id: 10,
            title: 'mytitle',
            sort_order: 200,
            childs: [],
          },
        ],
      },
    ];

here is my code

let flattenArray = [];

function flatten(a) {
  flattenArray.push(a);
  if (a.childs?.length) a.childs.map(flatten);
}

array?.map((el) => {
  flattenArray.push(el);
  if (el.childs?.length) el.childs.map(flatten);
});

console.log(flattenArray);

results :

[
    {
        "id": 1,
        "title": "t1",
        "sort_order": 200,
        "childs": [
            {
                "id": 2,
                "title": "t2",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 3,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 4,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 5,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 6,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            }
        ]
    },
    {
        "id": 2,
        "title": "t2",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 3,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 4,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 5,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 6,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 7,
        "title": "راهنما",
        "sort_order": "mytitle",
        "childs": [
            {
                "id": 8,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 9,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            },
            {
                "id": 10,
                "title": "mytitle",
                "sort_order": 200,
                "childs": []
            }
        ]
    },
    {
        "id": 8,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 9,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    },
    {
        "id": 10,
        "title": "mytitle",
        "sort_order": 200,
        "childs": []
    }
]
Shahmir
  • 31
  • 6