Categories
MongoDB

Using MongoDB with Mongoose — Populate Virtuals

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.

Populate Virtuals

We can control how 2 models are joined together.

For example, we can write:

async function run() {
  const { createConnection, Types, Schema } = require('mongoose');
  const db = createConnection('mongodb://localhost:27017/test');
  const PersonSchema = new Schema({
    name: String,
    band: String
  });

  const BandSchema = new Schema({
    name: String
  });

  BandSchema.virtual('members', {
    ref: 'Person',
    localField: 'name',
    foreignField: 'band',
    justOne: false,
    options: { sort: { name: -1 }, limit: 5 }
  });

  const Person = db.model('Person', PersonSchema);
  const Band = db.model('Band', BandSchema);
  const person = new Person({ name: 'james', band: 'superband' });
  await person.save();
  const band = new Band({ name: 'superband' });
  await band.save();
  const bands = await Band.find({}).populate('members').exec();
  console.log(bands[0].members);
}
run();

We create the PersonSchema as usual, but the BandSchema is different.

We call the virtual method with the join field call members to get the persons with the band name set to a given name.

The ref property is the name of the model we want to join.

localField is the field of the BandSchema that we want to join with PersonSchema .

The foreignField is the field of PersonSchema that we want to join with the BandSchema .

justOne means we only return the first entry of the join.

options has the options for querying.

Virtuals aren’t included in the toJSON() output by default.

If we want populate virtual to show when using functions that rely on JSON.stringify() , then add the virtuals option and set it to true .

For example, we can write:

async function run() {
  const { createConnection, Types, Schema } = require('mongoose');
  const db = createConnection('mongodb://localhost:27017/test');
  const PersonSchema = new Schema({
    name: String,
    band: String
  });

  const BandSchema = new Schema({
    name: String
  }, { toJSON: { virtuals: true } });

  BandSchema.virtual('members', {
    ref: 'Person',
    localField: 'name',
    foreignField: 'band',
    justOne: false,
    options: { sort: { name: -1 }, limit: 5 }
  });

  const Person = db.model('Person', PersonSchema);
  const Band = db.model('Band', BandSchema);
  const person = new Person({ name: 'james', band: 'superband' });
  await person.save();
  const band = new Band({ name: 'superband' });
  await band.save();
  const bands = await Band.find({}).populate('members').exec();
  console.log(bands[0].members);
}
run();

to add the virtuals option to the BandSchema .

If we use populate projections, then foreignField should be included in the projection:

async function run() {
  const { createConnection, Types, Schema } = require('mongoose');
  const db = createConnection('mongodb://localhost:27017/test');
  const PersonSchema = new Schema({
    name: String,
    band: String
  });

  const BandSchema = new Schema({
    name: String
  }, { toJSON: { virtuals: true } });

  BandSchema.virtual('members', {
    ref: 'Person',
    localField: 'name',
    foreignField: 'band',
    justOne: false,
    options: { sort: { name: -1 }, limit: 5 }
  });

  const Person = db.model('Person', PersonSchema);
  const Band = db.model('Band', BandSchema);
  const person = new Person({ name: 'james', band: 'superband' });
  await person.save();
  const band = new Band({ name: 'superband' });
  await band.save();
  const bands = await Band.find({}).populate({ path: 'members', select: 'name band' }).exec();
  console.log(bands[0].members);
}
run();

We call populate with an object with the path to get the virtual field and the select property has a string with the field names that we want to get separated by a space.

Conclusion

We can use Mongoose populate virtual feature to join 2 models by a column other than an ID column.

Leave a Reply

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