To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.
In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.
Populating an Existing Document
We can call populate
on an existing document.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = connection.model('Story', storySchema);
const Person = connection.model('Person', personSchema);
const author = new Person({
_id: new Types.ObjectId(),
name: 'James Smith',
age: 50
});
await author.save();
const fan = new Person({
_id: new Types.ObjectId(),
name: 'Fan Smith',
age: 50
});
await fan.save();
const story1 = new Story({
title: 'Mongoose Story',
author: author._id,
});
story1.fans.push(fan);
await story1.save();
const story = await Story.findOne({ title: 'Mongoose Story' })
await story.populate('fans').execPopulate();
console.log(story.populated('fans'));
console.log(story.fans[0].name);
}
run();
We created the story with the fans
and author
field populated.
Then we get the entry with the Story.findOne
method.
Then we call populate
in the resolved story
object and then call execPopulate
to do the join.
Now the console log should see the fans
entries displayed.
Populating Multiple Existing Documents
We can populate across multiple levels.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const userSchema = new Schema({
name: String,
friends: [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
const User = connection.model('User', userSchema);
const user1 = new User({
_id: new Types.ObjectId(),
name: 'Friend',
});
await user1.save();
const user = new User({
_id: new Types.ObjectId(),
name: 'Val',
});
user.friends.push(user1);
await user.save();
const userResult = await User.
findOne({ name: 'Val' }).
populate({
path: 'friends',
populate: { path: 'friends' }
});
console.log(userResult);
}
run();
We have a User
schema that is self-referencing.
The friends
property references the User
schema itself.
Then when we query the User
, we call populate
with the path
to query.
We can query across multiple levels with the populate
property.
Cross-Database Populate
We can populate across databases.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db1 = createConnection('mongodb://localhost:27017/db1');
const db2 = createConnection('mongodb://localhost:27017/db2');
const conversationSchema = new Schema({ numMessages: Number });
const Conversation = db2.model('Conversation', conversationSchema);
const eventSchema = new Schema({
name: String,
conversation: {
type: Schema.Types.ObjectId,
ref: Conversation
}
});
const Event = db1.model('Event', eventSchema);
const conversation = new Conversation({ numMessages: 2 });
conversation.save();
const event = new Event({
name: 'event',
conversation
})
event.save();
const events = await Event
.findOne({ name: 'event' })
.populate('conversation');
console.log(events);
}
run();
We create 2 models with the Coversation
and Event
models that are linked to different database connections.
We can create the Conversation
and Event
entries and link them together.
And then we can call findOne
on Event
to get the linked data.
Conclusion
We can populate existing documents and populate across databases with Mongoose.