0

I have two arrays of objects that I need to merge together to only get one array of object. There is a lot of objects, both have more than 500+ objects

This is an exemple of the structure of the two array of objects :

let API = [
  {
    actif: true,
    id: 8,
    creation_user: "David",
    date_creation: "févr  4 2022 12:17PM",
    description: "A description",
    version: "v1r1"
  },
  {
    actif: true,
    id: 10,
    creation_user: "Julien",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  },
  {
    actif: false,
    id: 20,
    creation_user: "Tom",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  }
]

let Parameters = [
  {
    id: 10,
    name: "codeRR",
    type: "string"
  },
  {
    id: 20,
    name: "codeAA",
    type: "string"
  },
  {
    id: 20,
    name: "codeCC",
    type: "string"
  }
]

As we can see, they both have an ID, this ID is the same in both arrays. But not everytime, API can have no parameter.

What i'm trying to achieve is to get in the second array, the "name" and "type", and to add it to the first array (or in a new array).

I've tried with .map on the first array (also tried with the second one) :

let Ressource = api.map(item => Object.assign({}, item, parametre.find(target => target.id === item.id)));
 
 // Result of Ressource
 
 [
  {
    actif: true,
    id: 8,
    creation_user: "David",
    date_creation: "févr  4 2022 12:17PM",
    description: "A description",
    version: "v1r1";
    name: "codeRR",
    type: "string
  }
 ]
 
 // Want I want :
 [
  {
    actif: true,
    id: 8,
    creation_user: "David",
    date_creation: "févr  4 2022 12:17PM",
    description: "A description",
    version: "v1r1",
    parameter: [
      {
        name: "codeRR",
        type: "string
      },
      {
        name: "codePP",
        type: "string
      }
    ]
  }
 ]

But when an API have multiple parameter it overwrite the previous one. Is it possible to make something like this in my API

parameter: [{"name": "codeRR", type: "string"}, {"name": "codePP", "type": "string"}]
Quentin
  • 321
  • 6
  • 18
  • **A)** `id = 8` is present in `API` but not present in `Parameters` array. So, how do we get the resulting `Resource` to have `name: codeRR` for `id = 8`? **B)** Would you please update the question with what is expected result for `id = 20`?. – jsN00b May 31 '22 at 07:36
  • Does this answer your question? [JavaScript merging objects by id](https://stackoverflow.com/questions/19480008/javascript-merging-objects-by-id) – pilchard May 31 '22 at 07:38
  • yes, id = 8 is not present in Parameters because sometime API doesn't have a parameter, I will edit my question. – Quentin May 31 '22 at 07:39
  • also [Merge two array of objects based on a key](https://stackoverflow.com/questions/46849286/merge-two-array-of-objects-based-on-a-key) – pilchard May 31 '22 at 07:39

3 Answers3

1
  1. Group the Parameters array by their id using Array.prototype.reduce, this would give an object where the keys are the ids and the values are an array of parameter objects.

  2. Loop over the API array and using the object created above add the parameter property wherever the parameter information is available.

let 
  API = [
    { actif: true, id: 8, creation_user: "David", date_creation: "févr  4 2022 12:17PM", description: "A description", version: "v1r1" },
    { actif: true, id: 10, creation_user: "Julien", date_creation: "févr  10 2022 12:17PM", description: "A description", version: "v1r2" },
    { actif: false, id: 20, creation_user: "Tom", date_creation: "févr  10 2022 12:17PM", description: "A description", version: "v1r2" },
  ],
  Parameters = [
    { id: 10, name: "codeRR", type: "string" },
    { id: 20, name: "codeAA", type: "string" },
    { id: 20, name: "codeCC", type: "string" },
  ],
  ParametersGroup = Parameters.reduce((r, p) => ((r[p.id] ??= []).push(p), r), {}),
  APIWithParams = API.map((o) => ({
    ...o,
    ...(ParametersGroup[o.id] && { parameters: ParametersGroup[o.id] }),
  }));

console.log(APIWithParams);

If you want to handle single parameter and multiple parameters differently, then refer to the solution below:

let 
  API = [
    { actif: true, id: 8, creation_user: "David", date_creation: "févr  4 2022 12:17PM", description: "A description", version: "v1r1" },
    { actif: true, id: 10, creation_user: "Julien", date_creation: "févr  10 2022 12:17PM", description: "A description", version: "v1r2" },
    { actif: false, id: 20, creation_user: "Tom", date_creation: "févr  10 2022 12:17PM", description: "A description", version: "v1r2" },
  ],
  Parameters = [
    { id: 10, name: "codeRR", type: "string" },
    { id: 20, name: "codeAA", type: "string" },
    { id: 20, name: "codeCC", type: "string" },
  ],
  ParametersGroup = Parameters.reduce((r, p) => ((r[p.id] ??= []).push(p), r), {}),
  APIWithParams = API.map((o) => {
    const paramsForId = ParametersGroup[o.id];
    return {
      ...o,
      ...(paramsForId && (paramsForId.length > 1 ? { parameters: paramsForId } : paramsForId[0])),
    };
  });

console.log(APIWithParams);

Note: Finding the parameter for an id again and again is not optimal. Hence we've created an object beforehand and referenced it while adding the parameter information.

Other relevant documentations:

SSM
  • 2,855
  • 1
  • 3
  • 10
  • Thanks you for the documentation, I truly need it, always having a bad time performing such merge and arrays of objects in general. – Quentin May 31 '22 at 08:15
  • 1
    @Quentin I've also added a *note* in my answer, I'd recommend going through that. Since you mentioned that the arrays could be large, it's *not* optimal to `find` or `filter` (_or anything that takes linear time_) again and again. – SSM May 31 '22 at 08:22
  • 1
    I see, again, thanks you, I was a bit concerned about performance since it's was taking some time to build the array with a `find` or `filter`. Will read and take note from your links ! – Quentin May 31 '22 at 08:40
  • By the way, is there any optimal way to display all of the array ? – Quentin May 31 '22 at 09:00
  • You want to render thousands of items at once? Usually that's *not* required and only a portion of the data is rendered at once. But in case you want to render everything at once, you can. – SSM May 31 '22 at 11:29
  • Well, it's not everything, but the majority of it. Like i'm displaying every api with every parameters. – Quentin May 31 '22 at 11:50
  • @Quentin Okay, you can render everything that shouldn't be a problem but make sure you opt out of unnecessary re-renders by memoizing the component that renders all these items. – SSM May 31 '22 at 13:09
1

If the parameters have the same attributes they will be overwritten.

if you need both of them you need to store them in an array

like this

const decorate = (data, parameters) => data.map(d => ({...d, parameters: parameters.filter(({id}) => d.id === id)}))




let API = [
  {
    actif: true,
    id: 8,
    creation_user: "David",
    date_creation: "févr  4 2022 12:17PM",
    description: "A description",
    version: "v1r1"
  },
  {
    actif: true,
    id: 10,
    creation_user: "Julien",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  },
  {
    actif: false,
    id: 20,
    creation_user: "Tom",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  }
]

let Parameters = [
  {
    id: 10,
    name: "codeRR",
    type: "string"
  },
  {
    id: 20,
    name: "codeAA",
    type: "string"
  },
  {
    id: 20,
    name: "codeCC",
    type: "string"
  }
]

console.log(decorate(API,Parameters ))
R4ncid
  • 6,944
  • 1
  • 4
  • 18
  • Solved my problems with your code, so `filter` was far better than just a `find`. And yes, i need both, making sure I don't miss something – Quentin May 31 '22 at 08:17
1

You're almost there. You can add extra logic for your map to handle multiple and single parameters separately.

let API = [{
    actif: true,
    id: 8,
    creation_user: "David",
    date_creation: "févr  4 2022 12:17PM",
    description: "A description",
    version: "v1r1"
  },
  {
    actif: true,
    id: 10,
    creation_user: "Julien",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  },
  {
    actif: false,
    id: 20,
    creation_user: "Tom",
    date_creation: "févr  10 2022 12:17PM",
    description: "A description",
    version: "v1r2"
  }
]

let Parameters = [{
    id: 10,
    name: "codeRR",
    type: "string"
  },
  {
    id: 20,
    name: "codeAA",
    type: "string"
  },
  {
    id: 20,
    name: "codeCC",
    type: "string"
  }
]

const result = API.map((data) => {
  const updatedData = Object.assign({}, data)
  const foundParameters = Parameters.filter(({
    id
  }) => id === data.id)
  if (foundParameters.length === 0) {
    return data
  }

  if (foundParameters.length === 1) {
    return Object.assign(updatedData, foundParameters[0])
  } else {
    return Object.assign(updatedData, {
      parameter: foundParameters.map(({
        name,
        type
      }) => ({
        name,
        type
      }))
    })
  }
});

console.log(result)
Nick Vu
  • 14,512
  • 4
  • 21
  • 31