【发布时间】:2019-10-22 04:32:27
【问题描述】:
我从我的应用中调用了一个查询,以向我提供来自我的数据库的分页结果
const query = [
{
"$match" : {
"$or" : [
{ "expires_at" : { "$gt" : moment().toISOString() }},
{ "expires_at" : null }
],
"vendor_category" : {
"$nin" : ignoredCategories
}
}
},
{
"$lookup": {
"from": models.retailers.collection.name,
"localField": "retailer",
"foreignField": "_id",
"as": "retailer"
}
},
{
"$lookup": {
"from": models.categories.collection.name,
"localField": "category",
"foreignField": "_id",
"as": "category"
}
},
{
"$sort": {
"category.popularity" : -1,
...sortBy
}
},
{ "$unwind": "$retailer" },
{ "$unwind": "$category" },
{ "$skip" : skip },
{ "$limit" : limit }
]
这很有效,我的两个 $lookup 和 $unwind 对象将其他集合加入到结果中,我的 $sort 对象正确地按产品类别流行度对根查询进行排序。
但是,我的 $match 对象仅返回大约 18 个(共 72 个)结果。除了当我运行const total = await models.products.countDocuments(query[0].$match) 时,这很好,所以使用该匹配查询计算文档,我得到 72。所以两者之间存在不匹配。
那么其余的结果会怎样呢?我在这个查询中做错了吗?这绝对是我写的第一个聚合查询,所以也许我只是完全错过了一些东西。欢迎任何提示/问题/优化!如果您需要更多信息,请告诉我。
编辑
这是扩展匹配查询的示例。当我使用Model.find 时,它工作正常,但由于我一直在隔离部分查询,这似乎是罪魁祸首。目的是仅提取过期时间大于当前时间的结果,或者该字段为空。数据来自刮板,有时我没有过期数据。我还排除了一系列类别,这是为了防止显示通过刮板但我不想出现在网站上的项目。
$match : {
$or : [
{ expires_at : { $gt : moment().toISOString() }},
{ expires_at : null }
],
vendor_category : {
$nin : [ 'ID-6', 'ID-8', 'ID-283', 'ID-288', 'ID-354', 'ID-513', 'ID-654', 'ID-659', 'ID-33', 'ID-450', 'ID-497', 'ID-59', 'ID-404', 'ID-337']
}
}
【问题讨论】:
-
是否有可能某些类别或零售商不存在于另一个集合中。是的,
$unwind是这里出现问题的原因。 -
docs.mongodb.com/manual/core/aggregation-pipeline-optimization 没有回答这个问题,但值得一读。你怎么知道第一阶段返回“大约 18 个结果”?
-
所以我接受,你的问题只是关于 $match 查询?常规查询和聚合查询之间存在一些细微的实现差异,这可能会干扰这里。你能给我们举一个被忽略的类别的例子吗?另外,您确定“expires_at”将始终为“null”,还是根本不设置?
-
@BenSower 我更新了这个问题,提供了更多关于此的背景信息。当我完全删除匹配查询时,我得到了所有结果,分页工作正常。此外,当我将 vendor_category 查询留在那里时,它似乎也可以正常工作。所以
$or对象似乎是罪魁祸首。