Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

131
Views
Iterating through an object and updating values based on existing values

I have a data json object structured like this:

data: [{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=todd"
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=matt"
  },
  "visits": 5,
  "clicks": 17
},{
  "aggregate": {
    "path": "/home/page2",
    "query": ""
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page3",
    "query": "term=dig"
  },
  "visits": 2,
  "clicks": 20
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "term=dug"
  },
  "visits": 2,
  "clicks": 11
}]

I am looking to end up with an aggregatedObject object like this:

[{
  "path": "/home/page1",
  "visits": 9,
  "clicks": 24
},{
  "path": "/home/page2",
  "visits": 4,
  "clicks": 7
},{
  "path": "/home/page1",
  "visits": 4,
  "clicks": 31
}]

This is what I have so far:

let aggregatedObject = [];

_.each(data, function (item) {

  if (!_.find(aggregatedObject, { path: item.aggregate.path })) {
    aggregatedObject.push({
      path: item.aggregate.path,
      visits: item.visits,
      clicks: item.clicks
    });
    //console.log('not found');

  } else {
    // so lost here

  }
});

What I'm trying to do is if my new object doesn't have an item that matches the item I'm currently iterating through, I push it to the new object. So far I can successfully do this.

However, if I do find an item that matches the path in my new object (ignoring query), I have no idea how to update that item with the sum of the existing item's visits and clicks, and the one I'm iterating through.

about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

You can group based on path and add visits and clicks for same path using array#reduce.

const data = [{ "aggregate": { "path": "/home/page1", "query": "name=todd" }, "visits": 4, "clicks": 7 },{ "aggregate": { "path": "/home/page1", "query": "name=matt" }, "visits": 5, "clicks": 17 },{ "aggregate": { "path": "/home/page2", "query": "" }, "visits": 4, "clicks": 7 },{ "aggregate": { "path": "/home/page3", "query": "term=dig" }, "visits": 2, "clicks": 20 },{ "aggregate": { "path": "/home/page1", "query": "term=dug" }, "visits": 2, "clicks": 11 }],
    result = Object.values(data.reduce((r, o) => {
      const path = o.aggregate.path;
      r[path] ??= { path, visits: 0, clicks: 0};
      r[path].visits += o.visits;
      r[path].clicks += o.clicks;
      return r;
    },{}));
console.log(result);

about 4 years ago · Juan Pablo Isaza Report

0

I think you want to group data based on path, but your example result doesn't do that, it has two entries for "/home/page1" and none for "/home/page3", I'll assume that's just an error in the post.

You need to test to see if path already exists and if not, add a new aggregate object for it, then add clicks and visits.

Looking through the aggregated array every time for path can get expensive if the array gets very large, so consider making an index object of path to aggregated data array so it's just two lookups (once to get the index then another to get the object) rather than searching through the array every time. E.g. (no lodash I'm afraid):

let data = [{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=todd"
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "name=matt"
  },
  "visits": 5,
  "clicks": 17
},{
  "aggregate": {
    "path": "/home/page2",
    "query": ""
  },
  "visits": 4,
  "clicks": 7
},{
  "aggregate": {
    "path": "/home/page3",
    "query": "term=dig"
  },
  "visits": 2,
  "clicks": 20
},{
  "aggregate": {
    "path": "/home/page1",
    "query": "term=dug"
  },
  "visits": 2,
  "clicks": 11
}];

// Map of path to index in aggArr {path: index}
let pathMap = {};

// Get aggregated array data
let aggData = data.reduce((agg, obj) => {
  let path = obj.aggregate.path;
  
  // If not in index, add it and a new aggregation object
  if (!pathMap.hasOwnProperty(path)) {
    pathMap[path] = agg.length;
    agg.push({path: path, visits:0, clicks:0});
  }

  // target is for convenience, add visits and clicks
  let target = agg[pathMap[path]];
  target.visits += obj.visits; 
  target.clicks += obj.clicks;
  return agg;
}, []);

// Show result
console.log(aggData);

about 4 years ago · Juan Pablo Isaza Report

0

Map array with initial destructuring, using ES6 spread syntax. Then reduce accounting for paths previously traversed, summing visits and clicks on appropriate path.


 const res = data
     .map(({ aggregate, ...rest }) => ({ path: aggregate.path, ...rest }))
     .reduce((acc, c, i, arr) => {
         let curr = Object.assign({}, c);
         const traversed = acc.some(item => item.hasOwnProperty('path') && item.path === curr.path);
         if (traversed) return acc;

         arr.forEach((v, idx) => {
            if (idx !== i && c.path === v.path) {
               curr = { 
                  ...curr, 
                  visits: v.visits + curr.visits, 
                 clicks: v.clicks + curr.clicks 
                } 
           }
        })

       return [...acc, curr];
    }, [])

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!