2

I have an object of nested objects and would like to sort by one of the nested values (e.g. "month_sales" descending). This is what the data looks like:

{ 
"Bob": { sales: 13, revenue: 33, month_sales: 149 },
"Bill": { today_sales: 20, week_sales: 38, month_sales: 186 },
"Jane": { today_sales: 17, week_sales: 38, month_sales: 164 }
}

This is what I want it to look like (sort by month_sales descending):

{ 
"Bill": { today_sales: 20, week_sales: 38, month_sales: 186 },
"Jane": { today_sales: 17, week_sales: 38, month_sales: 164 }
"Bob": { sales: 13, revenue: 33, month_sales: 149 },
}

I have looked all over Google and StackOverflow, and have only found a couple answers that deal with sorting an object rather than an array, and in every case the answer has been along the lines of "write a function to convert the object to an array, sort that, and then turn it back into an object."

I'm willing to do that as a last resort, but it seems like I should be able to do this without deconstructing the entire object and putting it back together again. Maybe there's an elegant way to do this in lodash or something?

Chris
  • 1,273
  • 5
  • 19
  • 33
  • 1
    Please check this thread http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order – Chop Jul 22 '15 at 05:54

4 Answers4

1

This is not possible because properties of objects do not have a guaranteed order in javascript. You will have to convert it to an array perhaps like this first:

[ 
  { name: "Bob", sales: 13, revenue: 33, month_sales: 149 },
  { name: "Bill", today_sales: 20, week_sales: 38, month_sales: 186 },
  { name: "Jane", today_sales: 17, week_sales: 38, month_sales: 164 }
]

Then when you sort it as an array it will maintain that order.

Tom K
  • 430
  • 5
  • 22
1

You can only have sorted arrays, not objects. To do that, you first need to map your object to an array. Here's how you can do it using lodash map() and sortBy():

_(data)
    .map(function(value, key) {
        return _.defaults({ name: key }, value);
    })
    .sortBy('name')
    .value();
// →
// [
//   { name: "Bill", today_sales: 20, week_sales: 38, month_sales: 186 },
//   { name: "Bob", sales: 13, revenue: 33, month_sales: 149 },
//   { name: "Jane", today_sales: 17, week_sales: 38, month_sales: 164 }
// ]

The mapping uses the defaults() function to give each array item a new name property, which is used to sort the array.

Adam Boduch
  • 11,023
  • 3
  • 30
  • 38
0

If you convert your object to an array, then you could sort them by category like this

var arr = [ 
  { name: "Bob", sales: 13, revenue: 33, month_sales: 149 },
  { name: "Bill", today_sales: 20, week_sales: 38, month_sales: 186 },
  { name: "Jane", today_sales: 17, week_sales: 38, month_sales: 164 }
]

arr.sort(function(x, y){
    var category = "month_sales"
    if (x[category] < y[category]) {
        return -1;
    }
    if (x[category] > y[category]) {
        return 1;
    }
    return 0;
});
Chop
  • 509
  • 2
  • 7
0

While you can't sort an object, you can create an index sorted on whatever property you want, e.g. to get a list of the names sorted by month_sales highest to lowest:

var obj = { 
"Bob": { sales: 13, revenue: 33, month_sales: 149 },
"Bill": { today_sales: 20, week_sales: 38, month_sales: 186 },
"Jane": { today_sales: 17, week_sales: 38, month_sales: 164 }
}

var index = Object.keys(obj).sort(function(a,b) {
              return obj[b].month_sales - obj[a].month_sales;
            });

Then get the one with the highest value:

console.log(index[0] + ':' + obj[index[0]].month_sales); // Bill:186
RobG
  • 142,382
  • 31
  • 172
  • 209