Open In App

Mongoose Populate Virtuals

Last Updated : 28 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Mongoose Populate Virtuals refers to the ability to use the populate() method to populate virtual fields in your Mongoose models. Virtual fields, unlike regular fields, do not get stored in the database. Instead, they are computed on the fly based on other document data. In this article, we will explore Mongoose Populate Virtuals, a powerful feature that allows us to populate virtual properties in Mongoose models.

How to Use Mongoose Populate Virtuals?

The mongoose populate method can be used to fetch referenced documents and populate them in the query result. Virtuals are properties that are not persisted in the database but are computed on the fly by the model. To populate a virtual property, you can use the populate() method with an options object that has a path property that specifies the name of the virtual property to populate.

The path property should be set to the name of the virtual property prefixed with an underscore. Mongoose's populate() method allows you to populate a virtual property just as easily as you would populate a regular document reference field. However, populating a virtual field requires a slightly different setup. The virtual field is populated by specifying its path with an underscore (_) prefix.

Syntax:

Model.find(query)
.populate(path, select, model, match, options)
.exec(callback);

Parameters:

  • path (required) - The path to the field to populate. This can be a string or an object that specifies the path and any additional options.
  • select (optional) - The fields to include or exclude from the populated document. This can be a string or an object that specifies the fields to include or exclude.
  • model (optional) - The name of the model to use for populating the field, if different from the default model for the reference.
  • match (optional) - Additional conditions to match when populating the field. This can be an object that specifies the conditions to match.
  • options (optional) - Additional options for the query, such as limit or sort. This can be an object that specifies the query options.

Installation of mongoose module

To use Mongoose and start populating virtuals, you need to install the Mongoose package in your Node.js project. Here's how we can install Mongoose:

Step 1: We can install this package by using this command.

npm install mongoose

Step 2: After installing the mongoose module, you can check your mongoose version in the command prompt using the command.

npm version mongoose

Step 3: After that, you can just create a folder and add a file for example index.js, To run this file you need to run the following command.

node index.js

Project Structure: The project structure will look like this:

Example 1: Populating a Virtual Property for a Full Name

In this example the book.save() method takes a callback function that is executed after the book is saved to the database. Inside the callback, we call Book.findById and use the populate() method to fetch the book's author with the fullName virtual field. This code should log the book title and author's full name to the console without any errors.

Filename: Index.js

const mongoose = require("mongoose");
mongoose.set("strictQuery", true);
mongoose.connect(
"mongodb://localhost:27017/geeksforgeeks", {
useNewUrlParser: true,
});

// Define the User schema
const userSchema = new mongoose.Schema({
first: String,
last: String,
});

// Define a virtual field to retrieve
// the user's full name
userSchema.virtual("fullName").get(function () {
return `${this.first} ${this.last}`;
});

// Define the Book schema
const bookSchema = new mongoose.Schema({
title: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
});

// Define the User and Book models
const User = mongoose.model("User", userSchema);
const Book = mongoose.model("Book", bookSchema);

// Create a new user and save it to the database
const user = new User({ first: "John", last: "Doe" });
user.save();

// Create a new book and associate it with the user
const book = new Book({
title: "My Book Title",
author: user._id,
});
book.save((err) => {
if (err) console.error(err);

// Use the populate() method to fetch
// the book's author with the
// fullName virtual field
Book.findById(book._id)
.populate({
path: "author",
select: "first last",
})
.exec((err, book) => {
if (err) console.error(err);
console.log(book);
console.log(`Title: ${book.title}`);
console.log(`Author: ${book.author.fullName}`);
});
});

Steps to run:

Make sure you have installed the mongoose module using the following command:

npm install mongoose

Run the index.js file using the below command:

node index.js

Output:

Explanation:

In this example, we define a virtual property fullName in the User schema. When the Book document is populated, we use the populate() method to fetch the author field, which references the User model. By using the virtual field fullName, we are able to dynamically compute the full name without storing it in the database.

Example 2: Populating a Virtual Field with an Array of Posts

In this example, we create a new User document with an empty posts array and save it to the database. We then create a new Post document and save it to the database, and add the Post document id to the User's posts array. We save the User again, and then fetch it from the database, populating its posts field with the actual Post documents. The resulting document is logged to the console.

Filename: Index.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

mongoose.set("strictQuery", true);

const PostSchema = new Schema({
title: String,
content: String,
author: {
type: Schema.Types.ObjectId,
ref: "User",
},
});

// Define the User schema
const UserSchema = new Schema({
name: String,
email: String,
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});

// Define the models
const User = mongoose.model("User", UserSchema);
const Post = mongoose.model("Post", PostSchema);

mongoose
.connect("mongodb://localhost:27017/geeksforgeeks")
.then(() => {
console.log("Connected to Database");
// Create a new user
const user = new User({
name: "Bob",
email: "[email protected]",
posts: [],
});

// Save the user to the database
user.save((err, user) => {
if (err) {
console.log(err);
} else {
console.log("User saved:", user);

// Create a new post
const post = new Post({
title: "New Post",
content: "Content for new post",
author: user._id,
});

// Save the post to the database
post.save((err, post) => {
if (err) {
console.log(err);
} else {
console.log("Post saved:", post);

// Add the post to the user's posts array
user.posts.push(post._id);

// Save the user again
user.save((err, user) => {
if (err) {
console.log(err);
} else {
console.log("User with new post:", user);

// Populate the user's posts array with
// actual post documents
User.findById(user._id)
.populate("posts")
.exec((err, user) => {
if (err) {
console.log(err);
} else {
console.log(
"User with populated posts:",
user
);
}
mongoose.disconnect();
});
}
});
}
});
}
});
})
.catch((err) => {
console.error("Error connecting to the database", err);
});

Steps to run:

Run the following command:

node index.js

Output:

Explanation: In this example, we created a virtual field postsArray in the User schema to populate all posts related to a specific user. The virtual field is populated using the populate() method, which retrieves the post documents and displays them within the postsArray field.

Conclusion

Mongoose Populate Virtuals is a powerful feature that allows you to populate dynamic, computed properties without storing them in the database. By using the get() and set() methods to create virtual fields, and then using populate() to dynamically retrieve data, you can simplify data management and retrieval in your Mongoose models. Populating virtual fields is especially useful for cases where you want to enrich your data with computed or related information without directly modifying your database schema.


Next Article

Similar Reads