Grouping Results in Mongoose (with examples)

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

Grouping results in MongoDB can be a powerful tool for data analysis and manipulation. Mongoose, a popular ODM library for MongoDB and Node.js, supports aggregation and grouping through its intuitive API. This tutorial will walk you through various examples showcasing how to use grouping in Mongoose effectively.

Getting Started

Before grouping results, ensure you have Mongoose and a MongoDB instance set up. Use the following code snippet to initiate a connection to your database:

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/myDatabase', { useNewUrlParser: true, useUnifiedTopology: true });

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
  // we're connected!
  console.log('Connected to the database');
});

Basic Grouping with Aggregation

Let’s consider a simple example where we have a collection ‘User’, which stores user details.

const userSchema = new mongoose.Schema({
  name: String,
  age: Number,
  country: String
});

const User = mongoose.model('User', userSchema);

To group users by country and count them, follow this aggregate pipeline:

const groupByCountry = async () => {
  try {
    const result = await User.aggregate([
      { $group: { _id: '$country', count: { $sum: 1 } } }
    ]);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};

groupByCountry();

Advanced Groupings

For more complex grouping, you can add additional stages to the pipeline, including match, sort, and project stages:

const advancedGrouping = async () => {
  try {
    const result = await User.aggregate([
      { $match: { age: { $gt: 18 } } },
      { $group: { _id: '$country', avgAge: { $avg: '$age' } } },
      { $sort: { avgAge: -1 } }
    ]);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};

advancedGrouping();

Grouping and Populating References

Often, you would need to populate documents referenced by ObjectId in the grouping process. Mongoose enables this as shown below:

const groupAndPopulate = async () => {
  try {
    const result = await User.aggregate([
      // Assuming users have posts referenced by ObjectId
      { $lookup: { from: 'posts', localField: '_id', foreignField: 'user', as: 'posts' } },
      { $unwind: '$posts' },
      // Now group by user id and count their posts
      { $group: { _id: '$_id', postCount: { $sum: 1 } } },
      { $sort: { postCount: -1 } }
    ]);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};

groupAndPopulate();

When performing group operations, it’s important to consider the potential impact on performance. Ensure appropriate indexes are in place to optimize the aggregation queries.

Using Grouping with MapReduce

Mongoose also allows grouping through the MapReduce paradigm:

const mapReduceExample = async () => {
  const mapFunction = function() { emit(this.country, 1); };
  const reduceFunction = function(keyCountry, countArray) { return Array.sum(countArray); };

  try {
    const result = await User.mapReduce({
      map: mapFunction,
      reduce: reduceFunction
    });
    console.log(result);
  } catch (error) {
    console.error(error);
  }
};

mapReduceExample();

Conclusion

In this guide, we explored the essentials of grouping results in Mongoose with practical examples. Remember, the more complex your queries, the more thought you should put into the performance implications. Happy coding!