我在房产模型和销售模型之间有父级参考关系。在我的销售模型中,我包含一个引用父属性的字段:
property: {
type: mongoose.Schema.ObjectId,
ref: "Property",
required: [true, "Sale must belong to a property"],
}
在我的销售模型的最后,我包含了一个 mongoose 预查找中间件来填充引用属性的名称,以便可以在查询中对其进行过滤:
saleSchema.pre(/^find/, function (next) {
this.populate({
path: "property",
select: "propInfo.propName",
});
next();
});
我想向我的销售路由器提交请求以退回仅适用于该房产名称的销售:
{{URL}}api/v1/sales?property.propInfo.propName=SampleName
当我向 {{URL}}api/v1/sales 发送 getAll 请求且参数中没有任何过滤器时,所有属性名称都将填充在响应中。
但是,每当我尝试按虚拟填充属性名称进行过滤或查询时,它都不会返回任何内容。看起来好像 Mongo 在查询后填充了父属性的字段,即使我有一个预查找中间件来填充虚拟值。
任何帮助或指导将不胜感激。
这是一个非常好的问题,但却是常见的误解。不幸的是,在这种情况下,
pre
钩子将populate
方法附加到
find
方法。因此,您无法查询填充的字段,因为在查询执行之前它们不会被添加。使用 mongoose
populate
,你无法根据子文档的查询条件过滤父文档。这是限制之一。值得庆幸的是,猫鼬模型有
Model.aggregate()
方法,这种事情非常简单。在下面的示例中,我假设您有
sales
集合和基于您的
properties
和
Sale
型号名称的
Property
集合。我还添加了一些额外的随机字段,例如
name
和
size
只是为了说明。
$lookup
:这与
populate
相同,其中针对
properties
集合进行查找,以将
Sales.property
字段与
Property._id
字段进行匹配。
$unwind
:将数组从
$lookup
变成对象。
$match
:现在您可以使用
propName
查询 SampleName
$project
:只输出你想要的字段。
const sales = await Sale.aggregate([
{
$lookup: {
from: "properties",
localField: "property",
foreignField: "_id",
as: "property"
}
},
{
$unwind: "$property"
},
{
$match: {
"property.propInfo.propName": SampleName
}
},
{
$project: {
"name": 1,
"property.propInfo.propName": 1,
"size": 1
}
}
])
请参阅