41

I have an array of JavaScript objects. My array is defined like this:

var myObjects = [
  { id: '1', username: 'bill.jones', active: true, createdon: '03/29/2014' },
  { id: '2', username: 'woohoo', active: true, createdon: '03/28/2014' },
  { id: '3', username: 'someuser', active: true, createdon: '03/30/2014' }
];

This array is actually dynamically populated. Still, I need to sort the results by the createdon value in ascending order. To do that, I'm trying to use lodash. The createdon value represents a date. Currently, I'm trying the following:

//  ORDER BY createdOn
myObjects.sort(function (a, b) {
  var date1 = new Date(a['createdon']);
  var date2 = new Date(b['createdon']);
  return date1 < date2;
});

_.forEach(myObjects, function(result) {
  console.log(result);
});

Unfortunately, myObjects is still not sorted after I run this function. What am I doing wrong?

Thank you!

user70192
  • 13,786
  • 51
  • 160
  • 240

2 Answers2

78

I just went through lodash doc, and perhaps you could try sortBy

Try it: http://jsfiddle.net/3Wza8/

var myObjects = [
    { id: '1', username: 'bill.jones', active: true, createdon: new Date('03/29/2014') },
    { id: '2', username: 'woohoo', active: true, createdon: new Date('03/28/2014') },
    { id: '3', username: 'someuser', active: true, createdon: new Date('03/30/2014') }
];

myObjects = _.sortBy(myObjects, 'createdon');

_.forEach(myObjects, function (result) {
    console.log(result);
});

EDIT: as Cookie Monster pointed out, it's important that your createdon field is a Date, and not a string.

lcoderre
  • 1,304
  • 9
  • 16
  • 1
    You're sorting by the string value, which can fail. http://jsfiddle.net/3Wza8/2/ You'll need to convert to dates first. – cookie monster Jul 03 '14 at 18:42
  • 3
    Well now you're changing the data structure. You should provide a solution that works for the actual situation presented. – cookie monster Jul 03 '14 at 18:56
  • 1
    I see your point, but given the question's context information, I think this is a potential solution for OP. Thanks though, I will keep that in mind. – lcoderre Jul 03 '14 at 19:12
  • 2
    It would work as a string if the dates are in a format like YYYYMMDD where a chronological sort = a string sort – Clyde D'Cruz Feb 07 '17 at 06:03
  • 1
    For me, I needed `desc` order, so I used `_.orderBy(arrOfObjs, 'sort_key', 'desc')`. This method is pretty powerful, you should check out the docs on it. –  Oct 24 '17 at 22:57
2

The problem is that sort expects a function which returns -1, 0 or 1. Your function only returns 0 and 1.

This slight change should fix it:

myObjects.sort(function (a, b) {
  var date1 = new Date(a['createdon']);
  var date2 = new Date(b['createdon']);
  return date1 - date2;
});
000
  • 26,951
  • 10
  • 71
  • 101
  • 1
    Why not just `return date1 - date2;`? – gen_Eric Jul 03 '14 at 18:35
  • I was under the assumption that sort expected -1, 0 or 1 – 000 Jul 03 '14 at 18:36
  • 1
    It just requires negative/positive numbers or `0`. But the return results between the same two items should always be the same. – cookie monster Jul 03 '14 at 18:37
  • doesn't this need to be the `date1.getTime()` so you're comparing milliseconds since epoch? – chovy Apr 01 '17 at 07:04
  • @chovy `Date` coerces to `Number`. `+new Date()` is a common idiom as a shortcut to `(new Date()).getTime()` – 000 Apr 01 '17 at 14:38
  • `new Date() + 1000 //=> "Sun Apr 02 2017 14:00:05 GMT-0700 (PDT)1000"` not what I would have expected. – chovy Apr 02 '17 at 21:00
  • Perhaps you know why that happens and you're stringing me along, but I'll bite. The `+` operator (by spec http://es5.github.io/#x11.6.1) first attempts to coerce to String, and then to Number. The `-` operator (spec http://es5.github.io/#x11.6.2) does not attempt to coerce to String. Which is why the code in my answer is just fine as-is. – 000 Apr 02 '17 at 21:09