假设我有以下文件。
{ "_id" : 1, "score" : [ -1, 3 ] }
{ "_id" : 2, "score" : [ 1, 5 ] }
{ "_id" : 3, "score" : [ 5, 5 ] }
{"_id" : 4, "score" : [ 2, 1, 5 ]}
如果我想查找包含得分数组中所有元素的文档介于3和6之间,那么如何使用{$gte:3}
和{$lte:6}
创建查询?
所以,它应该只返回:
{ "_id" : 3, "score" : [ 5, 5 ] }
答案 0 :(得分:0)
这里的一般情况是,您可能“应该”生成介于其间的“范围”,然后测试该数组不包含任何可能的数字:
var start = 3,
end = 6;
var range = Array(end - start + 1).fill(1).map(e => start++);
db.scores.find({
"score": {
"$elemMatch": { "$gte": start, "$lte": end },
"$not": {
"$elemMatch": { "$nin": range }
}
}
})
会回来:
{ "_id" : 3, "score" : [ 5, 5 ] }
因为这是唯一包含“仅”范围内的内容的元素。
如果您有一个限制,其中项目有太多可能的值来列出整个“范围”,那么您可以在“范围条件”上使用$not
:
db.scores.find({
"score": {
"$elemMatch": { "$gte": 3, "$lte": 6 },
"$not": {
"$elemMatch": {
"$not": { "$gte": 3, "$lte": 6 }
}
}
}
})
或者以额外的计算条件交替处理
使用$expr
:
db.scores.find({
"score": { "$elemMatch": { "$gte": 3, "$lte": 6 } },
"$expr": {
"$allElementsTrue": {
"$map": {
"input": "$score",
"in": {
"$and": [
{ "$gte": [ "$$this", 3 ] },
{ "$lte": [ "$$this", 6 ] }
]
}
}
}
}
})
MongoDB 3.6之前的$redact
db.scores.aggregate([
{ "$match": { "score": { "$elemMatch": { "$gte": 3, "$lte": 6 } } } },
{ "$redact": {
"$cond": {
"if": {
"$allElementsTrue": {
"$map": {
"input": "$score",
"in": {
"$and": [
{ "$gte": [ "$$this", 3 ] },
{ "$lte": [ "$$this", 6 ] }
]
}
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
甚至$where
使用JavaScript条件匹配MongoDB不支持以上任何内容的地方:
db.scores.find({
"score": { "$elemMatch": { "$gte": 3, "$lte": 6 } },
"$where": function() {
return this.score.every(e => e >= 3 && e <= 6)
}
})
在所有情况下,您实际上都希望$elemMatch
上出现“积极”条件,以便通过理想地搜索index on that field来查找“范围内”的元素。使用$not
和$nin
或通过$allElementsTrue
聚合条件或Array.every()
的其他方法都不能实际查看“索引”以满足条件。它们仅在所有情况下用作“附加过滤器”,通过最终结果中的“范围”从中“排除”任何“潜在”匹配文档。