1

I have an array of objects like below.

 [{
        "_id": {
          "$oid": "5d9a16764f66ef0017a738ee"
        },
        "user": "tVH3U5Va4cBFiATvAACD",
        "team": "team1",
        "question": "5d98c7109d0e1d0017e3d31f",
        "date": {
          "$date": "2019-10-06T16:29:40.240Z"
        },
        "correct": "true",
        "ownId": "4",
        "blockId": "1"
    },
    {
        "_id": {
          "$oid": "5d9a167c4f66ef0017a738ef"
        },
        "user": "tVH3U5Va4cBFiATvAACD",
        "team": "team1",
        "question": "5d98c7109d0e1d0017e3d31f",
        "date": {
          "$date": "2019-10-06T16:29:46.694Z"
        },
        "correct": "true",
        "ownId": "4",
        "blockId": "1"
    },
    {
        "_id": {
          "$oid": "5d9a16824f66ef0017a738f0"
        },
        "user": "tVH3U5Va4cBFiATvAACD",
        "team": "team1",
        "question": "5d98c7109d0e1d0017e3d31e",
        "date": {
          "$date": "2019-10-06T16:29:52.900Z"
        },
        "correct": "true",
        "ownId": "5",
        "blockId": "1"
    }]

I need to get objects with last date, which has unique user, ownId and blockId. By unique I mean that I will get only one user with same ownId same blockId. For this example I want to get only, since first object in array and last object in array has same user, ownId and blockId.

[{
            "_id": {
              "$oid": "5d9a167c4f66ef0017a738ef"
            },
            "user": "tVH3U5Va4cBFiATvAACD",
            "team": "team1",
            "question": "5d98c7109d0e1d0017e3d31f",
            "date": {
              "$date": "2019-10-06T16:29:46.694Z"
            },
            "correct": "true",
            "ownId": "4",
            "blockId": "1"
        },
        {
            "_id": {
              "$oid": "5d9a16824f66ef0017a738f0"
            },
            "user": "tVH3U5Va4cBFiATvAACD",
            "team": "team1",
            "question": "5d98c7109d0e1d0017e3d31e",
            "date": {
              "$date": "2019-10-06T16:29:52.900Z"
            },
            "correct": "true",
            "ownId": "5",
            "blockId": "1"
        }]

What I tried is to itterate through array, but this way I can get only unique object within one key. I can't figure out how to have it with few keys.

stat.forEach(function(item) {
  var i = unique.findIndex(x => x.user == item.user);
  if (i <= -1) {
    unique.push({
      id: item._id,
      user: item.user
    });
  }
});
Angelzzz
  • 1,356
  • 2
  • 10
  • 20
  • 3
    Show us what you have tried. Stack Overflow isn't a free code writing service. The objective here is for you to show your own attempts to solve your own issue. Without showing any attempts it just looks like you want others to write all the code for you – charlietfl Oct 06 '19 at 17:20
  • 1
    To add to Charlie's comment (and charlietfl is absolutely right, you need to show some of your work)...can you also expand a bit on what you are trying to do? Are you saying you want to filter out properties of the resulting object, in addition to the date comparison filter? Also this thread may help: https://stackoverflow.com/questions/36577205/what-is-the-elegant-way-to-get-the-latest-date-from-array-of-objects-in-client-s – Olivercodes Oct 06 '19 at 17:23
  • 1
    I added what I tried. In fasct I know how to filter array of objects with one key, but I can't figure out how to do it with few keys. – Angelzzz Oct 06 '19 at 17:25

2 Answers2

2

You can use reduce() method to iterate over the array building a hash table or object with user + ownId + blockId as property name or hash key.

While iterating, if object with same key exists, then compare the dates and replace the value with the object with latest date.

var data = [{ "_id": { "$oid": "5d9a16764f66ef0017a738ee" }, "user": "tVH3U5Va4cBFiATvAACD", "team": "team1", "question": "5d98c7109d0e1d0017e3d31f", "date": { "$date": "2019-10-06T16:29:40.240Z" }, "correct": "true", "ownId": "4", "blockId": "1" }, { "_id": { "$oid": "5d9a167c4f66ef0017a738ef" }, "user": "tVH3U5Va4cBFiATvAACD", "team": "team1", "question": "5d98c7109d0e1d0017e3d31f", "date": { "$date": "2019-10-06T16:29:46.694Z" }, "correct": "true", "ownId": "4", "blockId": "1" }, { "_id": { "$oid": "5d9a16824f66ef0017a738f0" }, "user": "tVH3U5Va4cBFiATvAACD", "team": "team1", "question": "5d98c7109d0e1d0017e3d31e", "date": { "$date": "2019-10-06T16:29:52.900Z" }, "correct": "true", "ownId": "5", "blockId": "1" } ];

var result = Object.values(data.reduce((acc, curr) => {
  let value = acc[curr.user + curr.ownId + curr.blockId];

  if (!value || new Date(curr.date.$date) > new Date(value.date.$date)) {
    acc[curr.user + curr.ownId + curr.blockId] = curr;
  }

  return acc;
}, {}));

console.log(result);
Nikhil
  • 6,493
  • 10
  • 31
  • 68
1

Hopefully I have understood what your goal is. Something like this might work for you (I assumed your array of objects is called stat):

const seenOwnIds = [];
const seenBlockIds = [];
const seenUserIds = [];
const uniqueUserArray = [];

for (let obj of stat) {
    if ( seenOwnIds.includes(obj.ownId) || seenBlockIds.includes(obj.blockId) || seenUserIds.includes(obj.user) ) {
        continue;
    }
    else {
        seenOwnIds.push(obj.ownId);
        seenBlockIds.push(obj.blockId);
        seenUserIds.push(obj.user);
        uniqueUserArray.push(obj);
    }
};

let lastDate = null;
let lastDateObj = {};

for (let obj of uniqueUserArray) {
    const curDate = new Date(obj.date.$date);
    if ( lastDate == null || curDate > lastDate ) { 
        lastDate = curDate;
        lastDateObj = obj;
    }
}
Kevin
  • 141
  • 7
  • 1
    Your approach is interesting and I will defenetly remember it. But your code doesn't work, looks like it is better to use && instead of || inside if (at least it works closer to what I expected). Also it is better to sort array before this checking. Thank you – Angelzzz Oct 06 '19 at 18:25