Sorting results in Mongoose (ASC and DESC)

Updated: December 30, 2023 By: Guest Contributor Post a comment

Overview

Sorting queries is a fundamental aspect of working with databases. When using MongoDB with Mongoose in a Node.js environment, sorting results can be straightforward yet powerful for organizing your query returns. In this tutorial, we will cover how you can implement ascending and descending sort operations on your dataset using Mongoose and dive into more advanced scenarios to showcase how sorting can be used effectively.

Basic Sorting

Let’s begin with the basics. To sort documents in ascending or descending order using Mongoose, you can leverage the .sort() function, which can be chained after your query construction. Considering the usage of modern JavaScript and ES modules, let’s assume we have a model User:

import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
  username: String,
  createdAt: Date
});
const User = mongoose.model('User', userSchema);

To sort the users by creation date in ascending order:

User.find().sort({ createdAt: 'asc' }).exec();

And for descending order:

User.find().sort({ createdAt: 'desc' }).exec();

Sorting by Multiple Fields

Often, you may want to sort by more than one field. For instance, you may want users to be sorted by last name and then by first name, both in ascending order:

User.find().sort({ lastName: 'asc', firstName: 'asc' }).exec();

Using Sort With Select

You can also combine the .sort() with .select() to control which fields you want to retrieve from the documents:

User.find().sort({ createdAt: -1 }).select('username createdAt').exec();

Complex Sorting In Aggregations

When performing more elaborate queries using the aggregation framework, sorting fits right in as one of the pipeline stages. Here’s an example of sorting within an aggregation:

import mongoose from 'mongoose';

// Some more complex query
const ageAvgPerCountry = await User.aggregate([
  {
    $group: {
      _id: '$country',
      averageAge: { $avg: '$age' }
    }
  },
  {
    $sort: { averageAge: 1 }
  }
]);

Pagination and Sorting

Pagination often goes hand in hand with sorting. If you’re looking to display results in a paginated fashion, you’ll need to consider the sort order for consistency across pages. Here’s how you can do pagination with sorting:

const page = 1;
const limit = 10;

User.find()
  .sort({ createdAt: -1 })
  .skip((page - 1) * limit)
  .limit(limit)
  .exec();

Note: For production-grade pagination, you’ll want to look into more robust cursor-based pagination strategies.

Sorting with Custom Parameters

In real-world applications, you likely need to sort queries based on client inputs dynamically. For security and functionality, avoid directly passing client input to your sort methods. Here’s a method for implementing a safe, flexible sorting mechanism:

// a map of allowed sort fields
const sortables = { username: 'username', createdAt: 'createdAt' };
let sortBy = clientInput.sortBy;
let sortOrder = clientInput.sortOrder === 'asc' ? 1 : -1;

sortBy = sortables[sortBy] || 'defaultField';

User.find().sort({ [sortBy]: sortOrder }).exec();

Remember to sanitize and validate clientInput accordingly.

Conclusion

Sorting is an integral part of querying databases, and when using Mongoose, it can be extremely robust yet user-friendly. By mastering the sorting mechanisms that Mongoose offers, you can create everything from straightforward alphabetical listings through to more complex, multiple-field, and multi-directional sorts to fulfil any application’s requirement. Always remember to sanitize and validate any user input you use to shape queries, including sorting parameters. Armed with these techniques, your data will be displayed just as needed for the best user and developer experience.