Aw3same
Aw3same

Reputation: 1030

get multiple sums by multiple properties in array

I have a very difficult approach here. With this example data:

[
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 20,"numItems": 1},
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 65,"numItems": 20},
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 20,"numItems": 3},
    {"idClient": 1,"idProject": 1,"sourceLanguage": 26,"targetLanguage": 71,"numItems": 12},
    {"idClient": 2,"idProject": 3,"sourceLanguage": 20,"targetLanguage": 65,"numItems": 1}
]

I need to obtain multiples sums:

The example result should be something like:

[{
    "idClient": 1,
    "numItems": 36,
    "proyects": [
        {
            "idProyect": 8,
            "numItems": 24,
            "sourceLanguages":[
                {
                "id":26,
                "numItems": 21
                },
                {
                 "id": 30,
                "numItems": 3 
                }
            ]
        },
        {
            "idProject": 1,
            "numItems": 12,
            "sourceLanguages":[{
                "id":26,
                "numItems": 12,
                },
                {
                    "id": 30,
                    "numItems": 3, 
                }
                
            ]
        }]
}]

I have a simple function that can obtain the two first sums individually, and return in an object (removing idProject from the key to obtain the total per client):

const totalPerClient_Project= [...data.reduce((r, o) => {
        const key = o.idClient + '-' + o.idProject;

        const item = r.get(key) || Object.assign({}, o, {
          numItems: 0
        });

        item.numItems += o.numItems;

        return r.set(key, item);
      }, new Map).values()];

But I found very difficult to obtain the sum by 3 chained properties. Are this approach possible using an unique function?

Upvotes: 1

Views: 45

Answers (1)

Józef Podlecki
Józef Podlecki

Reputation: 11283

I think you can do all of that with one reduce function.

const data = [
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 20,"numItems": 1},
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 65,"numItems": 20},
    {"idClient": 1,"idProject": 8,"sourceLanguage": 26,"targetLanguage": 20,"numItems": 3},
    {"idClient": 1,"idProject": 1,"sourceLanguage": 26,"targetLanguage": 71,"numItems": 12},
    {"idClient": 2,"idProject": 3,"sourceLanguage": 20,"targetLanguage": 65,"numItems": 1}
]

const group1 = data.reduce((acc, value) => {
  let client = acc.find(pr => pr.idClient === value.idClient)
  
  if(!client) {
   client = {
    idClient: value.idClient,
    numItems: 0,
    projects: [],
   }
  
   acc.push(client);
  }
  
  client.numItems++;
  
  let project = client.projects.find(pr => pr.idProject === value.idProject)
  
  if(!project) {
   project = {
    idProject: value.idProject,
    numItems: 0,
    sourceLanguages: [],
   }
   
   client.projects.push(project);
  }
  
  project.numItems++;
  
  let sourceLanguage = project.sourceLanguages.find(pr => pr.id === value.sourceLanguage)
  
  if(!sourceLanguage) {
   sourceLanguage = {
    id: value.sourceLanguage,
    numItems: 0,
    sourceLanguages: [],
   }
   
   project.sourceLanguages.push(sourceLanguage);
  }
  
  sourceLanguage.numItems++;
  
  return acc;
}, [])

console.log(group1);

Upvotes: 1

Related Questions