1

I have the following object structure

{ "Apr-18" : { ... },
  "Jan-18" : { ... },
  "Feb-18" : { ... },
  ...
}

I am trying to sort the month (MMM-YY) keys so that it shows as follows

{ "Jan-18" : { ... },
  "Feb-18" : { ... },
  "Apr-18" : { ... },
  ...
}

My code for this is below. I am using moment.js to convert the date into its epoch for the sort comparison. I have roughly followed the solution shown here Sort JavaScript object by key However it's not working.

The console.log returns the object as it was, no sorting has occurred. What am I missing?

const object = { 
          "Apr-18" : { "a":"b" },
          "Jan-18" : { "c":"d" },
          "Feb-18" : { "e":"f" }
}

const sortObjectMonths = (obj) => Object.fromEntries(Object.entries(obj).sort( (a, b) => 
     Date.parse(moment(a, "MMM-YY") - Date.parse(moment(b, "MMM-YY")))
));

let sorted = sortObjectMonths(object)
console.log(sorted)
mcgovec9
  • 71
  • 7
  • 1
    `Object.entries` returns an array of tuples `[key, value]` your sort function is treating them as values. You'll need to sort by `a[1]` and `b[1]` for it to work. But even then you are relying on the ordering of Object keys which isn't ideal. – pilchard Aug 19 '21 at 10:04
  • object properties have no defined order – Bravo Aug 19 '21 at 10:06
  • That's not strictly true @Bravo. see: [Does JavaScript guarantee object property order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) (though as I noted in my comment, it's not the best option) – pilchard Aug 19 '21 at 10:07
  • Your data structure doesn't look right. – Oluwafemi Sule Aug 19 '21 at 10:08
  • yeah, sorry, it is defined, of course ... but you're right, not a good option – Bravo Aug 19 '21 at 10:09
  • I made you a snippet. Please make it a [mcve] – mplungjan Aug 19 '21 at 10:11
  • Ah my mistake, so in the example, the 'clientName' key can be ignored. so basically the object should be defined as `{"Apr-18": {}, "Jan-18" : {}, "Feb-18" : {} }` – mcgovec9 Aug 19 '21 at 10:30

3 Answers3

1

You can use Object.entries() to get the object property keys and values, then use Array.sort() to sort them using moment. We can simply subtract the moment values to sort them.

The Array.sort() accepts two arguments, firstEl, secondEl, in this case that will be [key1, value1], [key2, value2]. We can use destructuring to write these as ([a,],[b,]), where a and b are the object keys (e.g. 'Apr-18').

Then we'll use Object.fromEntries() to get our sorted object.

const object = { 
    "Apr-18" : { "a":"b" },
    "Jan-18" : { "c":"d" },
    "Feb-18" : { "e":"f" },
}

console.log('Original object:', object)

const sortedObject = Object.fromEntries(
    Object.entries(object).sort(([a,],[b,]) => { 
         return moment(a, "MMM-YY") - moment(b, "MMM-YY");
    })
)
console.log('Sorted object:', sortedObject)
        
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" referrerpolicy="no-referrer"></script>
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • 1
    You should explain your use of destructuring here for the OP. You could also address all of the small errors the OP was making. ie: not accessing the `clientname` object, the unnecessary `Date.parse()` calls etc. – pilchard Aug 19 '21 at 10:33
  • Good points @pilchard. I'll add some more details to the answer. – Terry Lennox Aug 19 '21 at 10:37
  • Including the clientname key was an error on my part, i've updated the question above to reflect this. Thanks for this answer. May I ask, what exactly is happening with the `[a,],[b,]` part ? - Answered, cheers! – mcgovec9 Aug 19 '21 at 10:40
  • 1
    We're using destructuring to write the .sort() arguments as [a,], [b,]. One could also write these as [keya,valuea],[keyb, valueb] where keya would be 'Apr-18' etc. I hope that explains things a little! – Terry Lennox Aug 19 '21 at 10:44
  • Ah, yes, that's fixed. Thank you @mplungjan. – Terry Lennox Aug 19 '21 at 10:48
1

Without moment

const months = ["Jan","Feb","Mar","Apr"]

const object = { 
    "Apr-18" : { "a":"b" },
    "Jan-18" : { "c":"d" },
    "Feb-18" : { "e":"f" },
}


const sortedObject = Object.fromEntries(
  Object.entries(object)
    .sort(([a,],[b,]) => months.indexOf(a.split("-")[0]) - months.indexOf(b.split("-")[0]))
)
console.log('Sorted object:', sortedObject)
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

Your code is almost okay but in .sort() the element a and b both are arrays of key and value. Key is at index 0 and value at index 1. Date.parse() won't work and converting the value by using new Date() is suggested. So, your code should be -

const moment = require("moment");

const sort = {
  clientname: {
    "Feb-18": { test: "c" },
    "Jan-18": { test: "a" },
    "Apr-18": { test: "v" },
  },
};

const sortObjectMonths = (obj) => {
  return Object.fromEntries(
    Object.entries(obj).sort(
      (a, b) => moment(new Date(a[0])) - moment(new Date(b[0]))
    )
  );
};

let sorted = sortObjectMonths(sort.clientname);
console.log(sorted);