我们当前有一个电影集合查询,以返回与用户生成的“compilations”中的标题匹配的“compilation”文档。
用户可以应用几个过滤器:访问群体、提供者和格式。
当前,此find()组合返回以下文档,即使匹配的“title”与筛选器不匹配,但“compilation”中的第二部电影与筛选器匹配。
{
"_id": "551781485d9d35e4720c9057",
"name": "Consciousness",
"audience": {
"adults": true,
"teenagers": true,
"kids": false
},
"compilation": [
{
"title": "2001",
"_id": "551781485d9d35e4720c9059",
"provider": {
"amazon": false,
"apple": true,
"hulu": false,
"google": true,
"xfinity": false
},
"format": {
"hd": false,
"sd": false,
"4k": true
}
},
{
"title": "Matrix",
"_id": "551781485d9d35e4720c9059",
"provider": {
"amazon": false,
"apple": true,
"hulu": false,
"google": true,
"xfinity": false
},
"format": {
"hd": true,
"sd": false,
"4k": false
}
}
]
}
如何重写它使$or+$和查询与$elemmatch特别相关?
它非常适用于只有一部电影,但没有多部电影的“汇编”。
Models.Movies.find(
{
"collection": {
"$elemMatch": {
"title": "2001"
}
}
}
)
.and([
{$or : audienceQuery},
{$or : providerQuery}
])
.and(formatQuery)
过滤查询如下所示:
audienceQuery == {"audience.adults":true}, {"audience.teenagers":true}, {"audience.kids":false};
providerQuery == {"compilation.provider.apple":true}, {"compilation.provider.google":true};
formatQuery == {"compilation.format.hd":true};
最佳答案
考虑使用aggregation framework可以利用管道阶段开始时的$match
操作进行早期筛选,以限制进入管道的文档。当放置在管道的开头时,$match
操作使用适当的索引来仅扫描集合中匹配的文档。您的第二个管道阶段将涉及对$unwind
数组使用compilation
操作,以便$match
操作的后续应用程序将过滤解构数组:剩余的管道操作$group
和$project
然后只传递来自以前筛选的输入文档和新计算的字段:
因此,聚合管道将如下所示:
Models.Movies.aggregate([
{
"$match": {
"compilation.title": "2001",
"$and": [
{ "$or": [{"audience.adults": true}, {"audience.teenagers": true}, {"audience.kids": false}] },
{ "$or": [{"compilation.provider.apple": true}, {"compilation.provider.google": true}] }
],
"compilation.format.hd": true
}
},
{
"$unwind": "$compilation"
},
{
"$match": {
"compilation.title": "2001",
"$and": [
{ "$or": [{"audience.adults": true}, {"audience.teenagers": true}, {"audience.kids": false}] },
{ "$or": [{"compilation.provider.apple": true}, {"compilation.provider.google": true}] }
],
"compilation.format.hd": true
}
},
{
"$group": {
"_id": {
"_id": "$_id",
"name": "$name",
"audience": "$audience"
},
"compilation": {
"$push": "$compilation"
}
}
},
{
"$project": {
"_id": "$_id._id",
"name": "$_id.name",
"audience": "$_id.audience",
"compilation": 1
}
}
])
结果:
/* 0 */
{
"result" : [
{
"_id" : "551781485d9d35e4720c9057",
"compilation" : [
{
"title" : "2001",
"_id" : "551781485d9d35e4720c9059",
"provider" : {
"amazon" : false,
"apple" : true,
"hulu" : false,
"google" : true,
"xfinity" : false
},
"format" : {
"hd" : true,
"sd" : false,
"4k" : true
}
}
],
"name" : "Consciousness",
"audience" : {
"adults" : true,
"teenagers" : true,
"kids" : false
}
}
],
"ok" : 1
}
关于node.js - Mongoose/MongoDB find()$或/$并在$ elemMatch内?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29328525/