DEV Community

Emeka Okwor
Emeka Okwor

Posted on

Dynamic Model Referencing with Mongoose

So, I had a mongoose schema that referenced multiple collections. I wanted a situation where I could populate the schema from these collections depending on the property value in the document. Did I confuse you? Oh, my bad, I'd give you a logical example.
Say we have a comment schema, and a user can comment on a blog post and a product. How can we populate the schema with the blog post comments or product comments programmatically? Well, now you see what I mean, right?.
It appears there is something called refPath. The refPath option is a more sophisticated alternative to ref. If ref is just a string, mongoose will always query the same model to find the populated sub documents. With refPath, you can configure what model Mongoose uses for each doc. It automatically instructs mongoose to look into an 'onModel' property to find the correct model to populate. For example, let's say we have a comment schema like so

const commentSchema = new Schema({
  body: { type: String, required: true },
  on: {
    type: Schema.Types.ObjectId,
    required: true,
    refPath: 'onModel'
  },
  onModel: {
    type: String,
    required: true,
    enum: ['BlogPost', 'Product']
  }
});

Enter fullscreen mode Exit fullscreen mode

Notice the property 'onModel'?. It defines the name of our models "BlogPost" and "Product" referenced in the schema like sorefpath:'onModel'.

Now, Let's create our models and add some data


// create models
const Product = mongoose.model('Product', new Schema({ name: String }));

const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));

const Comment = mongoose.model('Comment', commentSchema);

// add data to collections
const book = await Product.create({ name: 'The Count of Monte Cristo' });

const post = await BlogPost.create({ title: 'Top 10 French Novels' });

const commentOnBook = await Comment.create({
  body: 'Great read',
  on: book._id,
  onModel: 'Product'
});

const commentOnPost = await Comment.create({
  body: 'Very informative',
  on: post._id,
  onModel: 'BlogPost'
});


Enter fullscreen mode Exit fullscreen mode

We can query the comment schema, populate it with the data of a particular model we specified like so

const comments = await Comment.find().populate({ path: "BlogPost"})

Enter fullscreen mode Exit fullscreen mode

when you log comments, you should see something like this

// [ { _id: ....., on: { title: 'Top 10 French Novels' } }]

Enter fullscreen mode Exit fullscreen mode

Cool, init? I hope it helps someone out there. Happy coding.

Top comments (0)