I have a parent reference relationship between a property model and a sale model. Within my sale model, I include a field to reference the parent property:
property: {
type: mongoose.Schema.ObjectId,
ref: "Property",
required: [true, "Sale must belong to a property"],
}
At the end of my sale model, I include a mongoose pre find middleware to populate the name of the referenced property so that it can be filtered by in the query:
saleSchema.pre(/^find/, function (next) {
this.populate({
path: "property",
select: "propInfo.propName",
});
next();
});
I would like to submit a request to my sales Router to return sales that have only applied to that property name:
{{URL}}api/v1/sales?property.propInfo.propName=SampleName
When I send a getAll request to {{URL}}api/v1/sales without any filters in the parameters, all of the property names will be populated in the response.
However, whenever I try to filter or query by the virtual populated property name, it will not return anything. It seems as if Mongo is populating the fields of the parent property after the query, even though I have a pre find middleware to populate the virtuals.
Any help or guidance would be greatly appreciated.
This is a very good question but common misconception. Unfortunately, the
prehook in this case attaches thepopulatemethod to thefindmethod. As a result, you cannot query the populated fields as they will not be be added until after the query executes.With mongoose
populateyou cannot filter parent documents based on query conditions of child documents. This is one of the limitations.Thankfully, mongoose models have the
Model.aggregate()method where this kind of thing is pretty straightforward.In the example below I have assumed you have
salescollection and apropertiescollection based on yourSaleandPropertymodel names. I have also included some extra random fields such asnamejust for illustration.$lookup: this is the same aspopulatewhere a lookup is done against thepropertiescolletion to match theSale.propertyfield against theProperty._idfield.$unwind: turn the array from$lookupinto an object.$match: now you can query thepropNamewith yourSampleName$project: only output the fields you want.See HERE for a working example with some test data.