Categories
MongoDB

Using MongoDB with Mongoose — Dynamic References

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.

Dynamic References via refPath

We can join more than one model with dynamic references and the refPath property.

For example, we can write:

async function run() {
  const { createConnection, Types, Schema } = require('mongoose');
  const db = createConnection('mongodb://localhost:27017/test');
  const commentSchema = new Schema({
    body: { type: String, required: true },
    subject: {
      type: Schema.Types.ObjectId,
      required: true,
      refPath: 'subjectModel'
    },
    subjectModel: {
      type: String,
      required: true,
      enum: ['BlogPost', 'Product']
    }
  });
  const Product = db.model('Product', new Schema({ name: String }));
  const BlogPost = db.model('BlogPost', new Schema({ title: String }));
  const Comment = db.model('Comment', commentSchema);
  const book = await Product.create({ name: 'Mongoose for Dummies' });
  const post = await BlogPost.create({ title: 'MongoDB for Dummies' });
  const commentOnBook = await Comment.create({
    body: 'Great read',
    subject: book._id,
    subjectModel: 'Product'
  });
  await commentOnBook.save();
  const commentOnPost = await Comment.create({
    body: 'Very informative',
    subject: post._id,
    subjectModel: 'BlogPost'
  });
  await commentOnPost.save();
  const comments = await Comment.find().populate('subject').sort({ body: 1 });
  console.log(comments)
}
run();

We have the commentSchema that has the subject and subjectModel properties.

The subject is set to an object ID. We have the refPath property that references the model that it can reference.

The refPath is set to the subjectModel , and the subjectModel references the BlogPost and Product models.

So we can link comments to a Product entry or a Post entry.

To do the linking to the model we want, we set the subject and subjectModel when we create the entry with the create method.

Then we call populate with subject to get the subject field’s data.

Equivalently, we can put the related items into the root schema.

For example, we can write:

async function run() {
  const { createConnection, Types, Schema } = require('mongoose');
  const db = createConnection('mongodb://localhost:27017/test');
  const commentSchema = new Schema({
    body: { type: String, required: true },
    product: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'Product'
    },
    blogPost: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'BlogPost'
    }
  });
  const Product = db.model('Product', new Schema({ name: String }));
  const BlogPost = db.model('BlogPost', new Schema({ title: String }));
  const Comment = db.model('Comment', commentSchema);
  const book = await Product.create({ name: 'Mongoose for Dummies' });
  const post = await BlogPost.create({ title: 'MongoDB for Dummies' });
  const commentOnBook = await Comment.create({
    body: 'Great read',
    product: book._id,
    blogPost: post._id,
  });
  await commentOnBook.save();
  const comments = await Comment.find()
    .populate('product')
    .populate('blogPost')
    .sort({ body: 1 });
  console.log(comments)
}
run();

Then we set the product and blogPost in the same object.

We rearranged the commentSchema to have the products and blogPost references.

Then we call populate on both fields so that we can get the comments.

Conclusion

We can reference more than one schema within a schema.

Then we can call populate to get all the fields.

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 *