1

I have an array of objects and I want to sort it by date (in this case it's the property with occurredAt in it's name). Here is the array:

const arr = [
  {
    EmailCampaignEvents.campaignRef: "test6example1",
    EmailCampaignEvents.campaignSentAt: "2021-04-09T13:19:24.000",
    EmailCampaignEvents.customerRef: "Customer/activityTest10",
    EmailCampaignEvents.emailRef: "Email/9374eaee0713f36a247b0d0c863e920b",
    EmailCampaignEvents.eventType: "delivery",
    EmailCampaignEvents.occurredAt: "2021-04-09T13:19:25.000",
  },
  {
    Events.occurredAt: "2017-01-11T17:29:57.000",
    Events.productRef: "Event/201-13",
    Events.relatedEntityRefFlat: "Customer/201-5645307",
    Events.transactionCurrency: "SEK",
    Events.transactionItemCount: "4",
    Events.transactionItemPrice: "235.85",
    Events.type: "as.commerce.transaction.completed",
    relatedEventName: "Hammarby-Östersunds FK",
  },
  {
    Events.occurredAt: "2018-01-11T17:29:57.000",
    Events.productRef: "Event/201-13",
    Events.relatedEntityRefFlat: "Customer/201-5645307",
    Events.transactionCurrency: "SEK",
    Events.transactionItemCount: "2",
    Events.transactionItemPrice: "135.85",
    Events.type: "as.commerce.transaction.completed",
    relatedEventName: "Hammarby-Östersunds FK",
  },
];

Note that in the first object I have EmailCampaignEvents.occurredAt and in the rest two I have a property like this Events.occurredAt. Is it possible to sort this array somehow? Any example will be appreciated!

Milos
  • 569
  • 3
  • 8
  • 21

3 Answers3

2

The crux of the problem is the variable key names of the objects that store the occurredAt date values, you can define a custom method to get the values by checking for the substring in every object's keys.

const getOccurredAt = (obj) => {
  const key = Object.keys(obj).filter(k => k.includes('occurredAt'))[0];
  if (key) {
    return obj[key];
  }
  return null; // Set a default based on your use-case
}

arr.sort((x, y) => {
  const xVal = getOccurredAt(x);
  const yVal = getOccurredAt(y);
  return new Date(yVal) - new Date(xVal);
})

This would solve your problem, but I would definitely recommend having consistent key names for the same data across all objects, if possible.

Sahil Lamba
  • 96
  • 2
  • 6
1

Use Array.prototype.sort() with a custom sort function. You can use Object.keys() to find object keys that end in .occurredAt. Like so:

const arr = [
  {
    "EmailCampaignEvents.campaignRef": "test6example1",
    "EmailCampaignEvents.campaignSentAt": "2021-04-09T13:19:24.000",
    "EmailCampaignEvents.customerRef": "Customer/activityTest10",
    "EmailCampaignEvents.emailRef": "Email/9374eaee0713f36a247b0d0c863e920b",
    "EmailCampaignEvents.eventType": "delivery",
    "EmailCampaignEvents.occurredAt": "2021-04-09T13:19:25.000",
  },
  {
    "Events.occurredAt": "2017-01-11T17:29:57.000",
    "Events.productRef": "Event/201-13",
    "Events.relatedEntityRefFlat": "Customer/201-5645307",
    "Events.transactionCurrency": "SEK",
    "Events.transactionItemCount": "4",
    "Events.transactionItemPrice": "235.85",
    "Events.type": "as.commerce.transaction.completed",
    relatedEventName: "Hammarby-Östersunds FK",
  },
  {
    "Events.occurredAt": "2018-01-11T17:29:57.000",
    "Events.productRef": "Event/201-13",
    "Events.relatedEntityRefFlat": "Customer/201-5645307",
    "Events.transactionCurrency": "SEK",
    "Events.transactionItemCount": "2",
    "Events.transactionItemPrice": "135.85",
    "Events.type": "as.commerce.transaction.completed",
    relatedEventName: "Hammarby-Östersunds FK",
  },
]

arr.sort((a, b) => {
  const keyA = Object.keys(a).find((key) => key.endsWith('.occurredAt'))
  const keyB = Object.keys(b).find((key) => key.endsWith('.occurredAt'))
  const dateA = new Date(a[keyA])
  const dateB = new Date(b[keyB])
  return dateA - dateB // oldest to newest
})

console.log(arr)

Note that Array.prototype.sort() modifies the original array. You can use e.g. arr.slice().sort() to first create a copy of the array and then sort the copied array.

Matias Kinnunen
  • 7,828
  • 3
  • 35
  • 46
1

If there really are only 2 possibilities, you could just use a boolean or to fallback from the first to the second possibility:

const arr = [
  {
    "EmailCampaignEvents.campaignRef": "test6example1",
    "EmailCampaignEvents.campaignSentAt": "2021-04-09T13:19:24.000",
    "EmailCampaignEvents.customerRef": "Customer/activityTest10",
    "EmailCampaignEvents.emailRef": "Email/9374eaee0713f36a247b0d0c863e920b",
    "EmailCampaignEvents.eventType": "delivery",
    "EmailCampaignEvents.occurredAt": "2021-04-09T13:19:25.000",
  },
  {
    "Events.occurredAt": "2017-01-11T17:29:57.000",
    "Events.productRef": "Event/201-13",
    "Events.relatedEntityRefFlat": "Customer/201-5645307",
    "Events.transactionCurrency": "SEK",
    "Events.transactionItemCount": "4",
    "Events.transactionItemPrice": "235.85",
    "Events.type": "as.commerce.transaction.completed",
    "relatedEventName": "Hammarby-Östersunds FK",
  },
  {
    "Events.occurredAt": "2018-01-11T17:29:57.000",
    "Events.productRef": "Event/201-13",
    "Events.relatedEntityRefFlat": "Customer/201-5645307",
    "Events.transactionCurrency": "SEK",
    "Events.transactionItemCount": "2",
    "Events.transactionItemPrice": "135.85",
    "Events.type": "as.commerce.transaction.completed",
    "relatedEventName": "Hammarby-Östersunds FK",
  },
];

const result = arr.sort((a,b) => {
  const aVal = new Date(a["EmailCampaignEvents.occurredAt"] || a["Events.occurredAt"]);
  const bVal = new Date(b["EmailCampaignEvents.occurredAt"] || b["Events.occurredAt"]);
  return aVal - bVal;
});

console.log(result);
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 1
    All three answers are good, but this one suits best for my code structure. Thanks for your effort! – Milos Apr 21 '21 at 14:12