0

I have an array of JSON Objects that looks like the below sample:

    [ { _id: 58d98fc46cb2342d6848ae3,
    updateNumber: '1',
    resolution: 'tbd',
    nextUpdate: Mon Mar 27 2017 17:06:00 GMT-0400 (EDT),
    update: 'update 1',
    subject: 'test1',
    impact: 'test1',
    incidentNumber: '12345',
    wasNew: true,
    __v: 0 },
  { _id: 58d880126fb5087d684c8de4,
    updateNumber: '2',
    resolution: 'tbd',
    nextUpdate: Mon Mar 27 2017 18:06:00 GMT-0400 (EDT),
    update: 'update 2',
    subject: 'test1',
    impact: 'test1',
    incidentNumber: '12345',
    wasNew: true,
    __v: 0 },
  { _id: 58c23ae21bt2743d6328ae3,
    updateNumber: '1',
    resolution: 'tbd',
    nextUpdate: Mon Mar 27 2017 17:06:00 GMT-0400 (EDT),
    update: 'update 1',
    subject: 'test2',
    impact: 'test2',
    incidentNumber: '23456',
    wasNew: true,
    __v: 0 } ]

What I need to be able to do is for each incidentnumber, grab the latest update. Each incidentNumber will have multiple updates and I want to be able to retrieve the latest update (In the above example that is update 2 for incidentNumber 12345 and update 1 for incidentNumber 23456)

So far I have tried variations of _.max which will only work for one incidentNumber and not multiple.

I have searched extensively and so far have not found any questions that involved the same dataset I have.

Can anyone point me in the right direction on how to start solving this problem?

Thanks

1
  • you have to iterate to all list items, get the updateNumber. You just need to store the list Index for the highest where the updateNumber. then you know where in the list you need to get the incidentNumber`. Commented Mar 28, 2017 at 22:30

3 Answers 3

2

You can do this by first selecting the items with the incidentNumber that you want and then getting the one with the max updateNumber from those. In es6 syntax it would look something like this, assuming your data is in a data variable

data
 .filter(d => d.incidentNumber === '12345')
 .reduce((o, e) => o.updateNumber && o.updateNumber > e.updateNumber ? o : e, {})

In es5 syntax it's a bit more verbose

data
  .filter(function(d) { return d.incidentNumber === '12345'; })
  .reduce(function(o, e) { return  o.updateNumber && o.updateNumber > e.updateNumber ? o : e}, {})

Or you could do the filtering and getting max in one pass

data.reduce(function(o, e) { return (e.incidentNumber === '12345' &&  o.updateNumber && o.updateNumber > e.updateNumber) ? o : e}, {})

To get the object with the max updateNumber for each unique incident number you could maintain a hash of objects indexed by the incident number while you reduce

var results = data.reduce(function (m, e) {
    if (e.updateNumber && (!m[e.incidentNumber] || m[e.incidentNumber].updateNumber < e.updateNumber)) {
        m[e.incidentNumber] = e;
    }
    return m;
}, {});

Object.values(results); // will contain the array of objects with max updateNumber
Sign up to request clarification or add additional context in comments.

9 Comments

Personally I would do away with the filter callback and handle the filtering in the reduce callback instead. It'll save iterating through the data twice.
Yea, that would work too, this is slightly cleaner but you're right it would iterate twice. Let me update the answer with that version too
@gabesoft Maybe I am crazy and have no idea what I am talking about but I can't seem to get the example working. I tried it in jsfiddle with no luck, jsfiddle.net/danicela/atromdy0 Are you able to explain how the functions work? Would I not technically need a loop to go through each record?
There is a loop done implicitly within those functions. Which example did you try?
All you have to do to try is open the browser console, do var data = [...] to set the data variable to your data, and then run one of those examples. If you try to paste your sample data as is it won't work because the id fields and the nextUpdate fields need to be surrounded in quotes
|
0

The simplest (Fastest, and none destructive) way would be to use a map object, like this:

function getLatest(arr) {
  map = {};
    arr.forEach(item => {
    var i = item.incidentNumber;
    if (!map[i] || map[i].updateNumber<item.updateNumber) {
        map[i] = item;
    }
  })
  return Object.keys(map).map(key => map[key])
}

Comments

0

To get all incidents latest update, you can do the following where:

  • arr is your array of of incidents
  • id is your identifier
  • counter is what you are comparing the value of
function getLatestUpdate(arr, id, counter) {
  var _latest = [];
  var latest = [];

  while (arr.length) {
    var item = arr.shift();
    var currentUpdate = _latest[item[id]];

    _latest[item[id]] = (!currentUpdate) ? item : (currentUpdate[counter] > item[counter] ? currentUpdate : item);
  }

  for(key in _latest) {
    latest.push(_latest[key]);
  }

  return latest;
}

var latest = getLatestUpdate(arr, '_id', 'updateNumber');

If may not be the most efficient, but it takes advantage of arrays being objects and comparing the value of the object's counter while filtering through the array, then pushing the objects that exist to the array upon completion and destroying the key/value pairs that were being stored there.

4 Comments

I tried this one out and it seems to work! The only problem I can't resolve now is when i output the results of latest to the console, I seem to be getting hundreds of commas on new lines before the actual result. Any ideas?
@Dani could you post the exact code you are using? I didn't experience that when i was testing.
I put it in a jsfiddle to see. jsfiddle.net/danicela/hoqhaLv3 You can see the Array length is 23459
@Dani I updated my answer which solved the issue for me. Here, is the updated fiddle

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.