Sorting JavaScript Arrays By Nested Properties
September 30, 2021
Problem
Imagine you have an array of JavaScript objects and you need to sort the data, but the items you need to sort are not all top-level properties. Although there are native ways to sort, I wanted to show how to do some advanced sorting techniques using the lodash orderBy function. This function will not only let you sort multiple fields (each using asc or desc), but you can also sort by sub-properties.
Sample Data for Examples
I'll be using the following data when showing the various ways you can sort. The
data is an array of cities with weather information. There are some top level
properites of location
and description
, and then there is a nested current
object and a temps
array with high and low temperature information.
const items = [
{
location: "Nashville, TN",
description: "Clear",
current: { temp: 75, wind: 5 },
temps: [
{ type: "low", value: 68 },
{ type: "high", value: 88 }
],
},
{
location: "Prescott, AZ",
description: "Cloudy",
current: { temp: 68, wind: 2 },
temps: [
{ type: "low", value: 66 },
{ type: "high", value: 71 }
]
},
{
location: "Searcy, AR",
description: "Clear",
current: { temp: 75, wind: 0 },
temps: [
{ type: "low", value: 73 },
{ type: "high", value: 77 }
]
}
];
Sort by One Top Level Property via a String
This example is really nothing special. You could achieve this with a native
sorting algorithm in JavaScript, but I wanted to show how you can do it with the
lodash orderBy function. This will sort the items
array in ascending order
based on the top level location
property.
console.log(
orderBy(items, "location", "asc")
.map(({ location }) => location)
);
// ["Nashville, TN", "Prescott, AZ", "Searcy, AR"]
Sort by Two Top Level Properties
This is where the orderBy
function starts to shine. You can provide one or
more iteratees
to help the function to sort. This has the idea of a primary
sort, secondary sort, tertiary sort, etc... This is helpful to break the tie
when items share the same initial value. However, thus far the example is only
sorting top level props (description
and location
).
console.log(
orderBy(items, ["description", "location"], ["asc", "asc"])
.map(({ location }) => location)
);
// ["Nashville, TN", "Searcy, AR", "Prescott, AZ"]
Sort by a Function Returning a Nested Property
This example goes a little further and shows the technique of passing a function
(instead of a string) to indicate which field to sort. The first item digs into
the city (c
) and grabs it's current.temp
sub-property. The seconary sort is
the location
(both sorted in ascending order). You can mix and match the
function syntax along with the string version.
console.log(
orderBy( items, [c => c.current.temp, "location"], ["asc", "asc"])
.map(({ location }) => location)
);
// ["Prescott, AZ", "Nashville, TN", "Searcy, AR"]
Sort by a Nexted Property Using a String Path
Instead of using the function syntax, you could use the special string syntax
that inclues path information (current.temp
). Lodash is smart enough to
translate that to something like c => c.current.temp
like we had in the
previous example. This is a much cleaner and terse version of the function
syntax from the previous example.
console.log(
orderBy(items, ["current.temp", "location"], ["asc", "asc"])
.map(({ location }) => location)
);
// ["Prescott, AZ", "Nashville, TN", "Searcy, AR"]
Sort by a Function Returning an Array's Item Property
We can go one step further and use the function syntax to not only just grab a sub-property, but grab an item from an array and grab its property! Yeah, this gets a little involbed, but sometimes this is the type of thing that you need to do.
console.log(
orderBy(items, [(c) => c.temps[1].value, "location"], ["asc", "asc"])
.map(({ location }) => location)
);
// ["Prescott, AZ", "Searcy, AR", "Nashville, TN"]
Sort by a String Path Targeting an Array's Item Property
Finally, you can also use the string path syntax to access array items too! The
above example c => c.temps[1].value
can be replaced with a string of
"temps[1].value" and lodash will figure out what you meant! So cool!
console.log(
orderBy( items, ["temps[1].value", "location"], ["asc", "asc"])
.map(({ location }) => location)
);
// ["Prescott, AZ", "Searcy, AR", "Nashville, TN"]
NOTE: In all of these examples you could have used
asc
ordesc
for the ordering direction. Feel free to check out the official docs for more information.
Interactive CodeSandbox
I've taken the above examples and have put them into a CodeSandbox in case you want to take a look or play around with the samples.
Tweet about this post and have it show up here!