Sling Academy
Home/Node.js/Mongoose population explained (with examples)

Mongoose population explained (with examples)

Last updated: December 30, 2023

Mongoose is a robust tool for managing data relations in MongoDB. This article guides you through the concept of population in Mongoose, providing clear examples to illustrate this powerful feature effectively.

Understanding Population

Population is a process to automatically replace specified paths within a document with document(s) from other collection(s). In essence, it’s like a join in relational databases.

Basic Population

Let’s start with a simple example where you have two collections: Authors and Books.

const mongoose = require('mongoose');
const { Schema } = mongoose;

const AuthorSchema = new Schema({
  name: String
});
const BookSchema = new Schema({
  title: String,
  author: { type: Schema.Types.ObjectId, ref: 'Author' }
});

const Author = mongoose.model('Author', AuthorSchema);
const Book = mongoose.model('Book', BookSchema);

// To populate the author in the book query:
Book.find().populate('author').exec((err, books) => {
  if (err) return handleError(err);
  console.log('The author is %s', books[0].author.name);
  // Prints the author's name for the first book
});

Advanced Population

Population can go deeper with nested population and additional options like conditions, sorting, and field selection:

// Imagine a Book schema that also references a 'Publisher' model
Book.find()
  .populate({
    path: 'author',
    select: 'name -_id',
    populate: { path: 'publisher', select: 'name' }
  })
  .exec((err, books) => {
    // Handle result
  });

Population with Query Conditions

Applying query conditions to your population can help you fetch more specific data.

Book.find()
  .populate({
    path: 'author',
    match: { age: { $gte: 18 } },
    // Only populate authors older than 18
    select: 'name'
  })
  .exec((err, books) => {
    // books will have a null 'author' field if the condition is not met
  });

Handling Population in Asynchronous Functions

Using the async/await syntax, population becomes more readable:

const getBooks = async () => {
  try {
    const books = await Book.find().populate('author').exec();
    // Handle the populated books
  } catch (err) {
    // Error handling
  }
};

Conclusion

Mongoose population provides a convenient way to handle data relations, turning flat documents into rich, full-structured data. From basic usage to complex nesting, mastering population will immensely enhance your MongoDB applications.

Next Article: How to Perform Case-Insensitive Queries in Mongoose

Previous Article: Mongoose: 3 Ways to Remove All Documents from a Collection

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates