I would like to always populate subdocuments after saving a particular Model automatically. What I would really like is something like below:
MyModel.post('save', function(doc, next) {
doc.populate('path').then(next);
});
However, the above won't work because
post
middleware do not directly receive flow control, e.g. nonext
ordone
callbacks are passed to it.post
hooks are a way to register traditional event listeners for these methods.
Of course, there are "Asynchronous Post Hooks", but they still do not receive control flow so there is no guarantee the subdocuments will be populated when I need it.
Why not just use an embedded document? For this case, the subdocuments are the same as the parent document (e.g. I'm using something like the Composite pattern), which would cause a circular dependency that I'm not certain how to resolve (or if I can even resolve it). For other instances, I might want to be able to access the subdocuments without going through the parent document.
Another approach I considered is something like:
const nativeSave = /* ? */;
MyModel.methods.save = function save() {
return nativeSave.call(this).then(function(savedDoc) {
return savedDoc.populate('path');
});
};
However, there are two problems with this. First of all, it seems a like a round-about solution. If there is a more native approach that doesn't go against mongoose's implementation, I would prefer that. Secondly, I don't know what I would set nativeSave
to (as apparent by the /* ? */
).
So, what are some suggestions for getting this behavior? If my second solution would be the best with the current version of mongoose, what should I set nativeSave
to? I've already considered embedded documents, so please don't suggest using them unless you are providing a suggestion about resolving the circular dependency. Even then, I would like a solution for the other use-case I mentioned.
As explained in my comment, this is not the same as manually populating a subdocument after saving as other posts have asked. I want this to happen automatically to avoid leaking my implementation details (e.g. using ObjectIds instead of real documents).
I'm going to say that even if it were possible to monkeypatch a built in mongoose method like "save" or "find" it would probably be a terrible idea. Aside from the fact that not every call to the save method needs to incur the overhead of the extra populate call, you certainly wouldn't want to change the way the function works by dropping down to the underlying mongo driver (you lose validations, life cycle methods, and if you want to work with a mongoose document, you'll have to requery the database for it).
You run a huge risk breaking any code that depends on "save" working a certain way. All sorts of plugins are off the table, and you risk astonishing any developers that come after you. I wouldn't allow it in a codebase I was responsible for.
So you are left with create a static or schema method. In that method you'll call save, followed by populate. Something like this:
MyModel.methods.saveAndPopulate = function(doc) {
return doc.save().then(doc => doc.populate('foo').execPopulate())
}
That's pretty much the most up to date approach suggested here: Mongoose populate after save. That's why I voted to close your question.
This will help
http://frontendcollisionblog.com/mongodb/2016/01/24/mongoose-populate.html
var bandSchema = new mongoose.Schema({
name: String,
lead: { type: mongoose.Schema.Types.ObjectId, ref: 'person' }
});
var autoPopulateLead = function(next) {
this.populate('lead');
next();
};
bandSchema.
pre('findOne', autoPopulateLead).
pre('find', autoPopulateLead);
var Band = mongoose.model('band', bandSchema);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With