4

Context

Need to sort following Objects by readingDate using lodash, I'm able to sort it but its indexes are not preserved.

Original JSON Object

{
    "Inventory Creation": [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ],
    "Inventory & Check-in": [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    "Check-in": [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ]
}

Code Which I've Tried

_.sortBy(unsorted, o => o[0].readingDate).reverse();

here unsorted contains the above Orignal JSON object

Actual Result (What I'm getting)

{
    0: [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    1: [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ],
    2: [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ]
}

Expected Result (What I want)

{
    "Inventory & Check-in": [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    "Check-in": [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ],
    "Inventory Creation": [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ]
}
Hamid Ali
  • 835
  • 1
  • 7
  • 19
  • Your ***Original JSON Object*** is in fact an object, not an array, and `_.sortBy` returns an array after the sort. Why are you trying to sort an object? – Ghassen Louhaichi Jul 14 '20 at 10:24
  • Thanks for the correction, let me update the question, to make it more comprehensible. – Hamid Ali Jul 14 '20 at 10:46
  • No problem, although I still do not understand why you are trying to sort an object. – Ghassen Louhaichi Jul 14 '20 at 10:50
  • Actually its the requirement of task which I'm working on, I need to display above JSON object in a list, and that list should be sorted by `readingDate` – Hamid Ali Jul 14 '20 at 10:51
  • I see, well then just be careful that JavaScript ***does not*** always guarantee the order of object keys, especially when these keys are mixed between strings and numbers, as mentioned [here](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order). – Ghassen Louhaichi Jul 14 '20 at 10:54

3 Answers3

3

Here are the steps:

  • transform the object to list of key-value pairs (_.toPairs() or built-in's Object.entries())
  • sort the list
  • transform list of key-value pairs back to object (_.fromPairs() or built-in's Object.fromEntries())

Below snippet could help you. I use _.chain() for better readability

const data = {
  "Inventory Creation": [
    {
      id: 150,
      reading: "12345",
      readingDate: "2020-07-14",
    },
  ],
  "Inventory & Check-in": [
    {
      id: 151,
      reading: "12345",
      readingDate: "2020-11-14",
    },
  ],
  "Check-in": [
    {
      id: 152,
      reading: "12345",
      readingDate: "2020-08-14",
    },
  ],
}

const res = _.chain(data)
  .toPairs()
  .sortBy((p) => p[1][0].readingDate)
  .reverse()
  .fromPairs()
  .value()

console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js"></script>
hgb123
  • 9,840
  • 3
  • 11
  • 31
  • Excellent suggestion, it's worth noting though that this (or any other method) won't work if the keys have mixed types. For example, if we change the key `"Check-in"` to `1`, the output is wrong at the end, because of how objects work in JS. – Ghassen Louhaichi Jul 14 '20 at 11:00
2

This is a combination of collections/arrays. Look at the lodash function you are using and what it is used for. This cannot work, you are trying to use an array-function of an Object. The function does exactly what it should, sorting the array. But there is no way to create the sorted object this way, it (meaning the lodash function) doesn't even know about the object.

Having said this, here is a working solution (look at map/reduce in general):

const entries = Object.entries(unsortedArr);
const sorted = entries.sort((a,b) => a[1][0].readingDate < b[1][0].readingDate ? 1 : -1);
const reduced = sorted.reduce(
  (acc, obj) => {
    acc[obj[0]] = obj[1]
return acc},{});

Ofc you can chain these calls, but I tried to make it more understandable.
I just stumbled upon groupBy which could be used, too.

Dharman
  • 21,838
  • 18
  • 57
  • 107
Leviathan
  • 358
  • 2
  • 14
1

Here is a brute force solution. First sort the array and also store the keys. Then Form the array with keys from the sortedArray.

var sortedArray = _.sortBy(unsortedArray, function(val, key){
    val[0].key = key;
    return val[0].readingDate;
}).reverse();

var sortedArrayWithIndex = {};

_.each(sortedArray, function(val){
    var key = val[0].key;
    delete val[0].key;
    sortedArrayWithIndex[key] = val;
});
console.log(sortedArrayWithIndex);
Leon Talukdar
  • 173
  • 12