Sorting JavaScript Arrays By Nested Properties

Published

September 30, 2021

Reading time
4 min read
This post is part of my Byte Series, where I document tips, tricks, and tools that I've found useful.

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 or desc 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.

The above embed is hosted on CodeSandbox.
Web Mentions
0
0

Tweet about this post and have it show up here!