Categories
MongoDB

Using MongoDB with Mongoose — Populating Existing Documents and Across Databases

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *