Reputation: 1163
I have a simple relation between topics and categories when topic belongs to a category.
So schema looks like this:
const CategorySchema = new mongoose.Schema({
name: String,
slug: String,
description: String
});
And topic
const TopicSchema = new mongoose.Schema({
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
title: String,
slug: String,
body: String,
created: {type: Date, default: Date.now}
});
I want to implement particular embedding of category into topic
{
category: {
_id: ObjectId('abc'),
slug: 'catslug'
},
title: "Title",
slug: "topictitle",
...
}
It will help me avoid unnecessary population and obtain performance bonuses. I don't want to embed whole document because I want to changes categories sometimes (it is a rare operation) and maintain references.
Upvotes: 1
Views: 627
Reputation: 368
Hope this helps, done it in my own project to save some RTTs in common use cases. Make sure you're taking care of both copies on update.
parent.model.js:
const mongoose = require('mongoose');
const childEmbeddedSchema = new mongoose.Schema({
_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Child', auto: false, required: true, index: true},
someFieldIWantEmbedded: {type: String}
});
const parentSchema = new mongoose.Schema({
child: { type: childEmbeddedSchema },
moreChildren: { type: [{type: childEmbeddedSchema }] }
});
module.exports = mongoose.model('Parent', parentSchema);
child.model.js:
const mongoose = require('mongoose');
const childSchema = new mongoose.Schema({
someFieldIWantEmbedded: {type: String},
someFieldIDontWantEmbedded: {type: Number},
anotherFieldIDontWantEmbedded: {type: Date}
});
module.exports = mongoose.model('Child', childSchema);
parent.controller.js:
const mongoose = require('mongoose');
const Parent = require('path/to/parent.model');
exports.getAll = (req, res, next) => {
const query = Parent.find();
// only populate if requested! if true, will replace entire sub-document with fetched one.
if (req.headers.populate === 'true') {
query.populate({
path: 'child._id',
select: `someFieldIWantEmbedded ${req.headers.select}`
});
query.populate({
path: 'moreChildren._id',
select: `someFieldIWantEmbedded ${req.headers.select}`
});
}
query.exec((err, results) => {
if (err) {
next(err);
} else {
res.status(200).json(results);
}
});
};
Upvotes: 1