Mongodb 查询以查找所有数组属性元素都位于数组中的文档

Mongodb 查询以查找所有数组属性元素都位于数组中的文档,mongodb,Mongodb,我有一个收藏,里面有这样的文件: { _id : "1", arrayProperty : ["1","2","3"] } 我想找到一些数组中包含所有arrayProperty元素的文档 假设我有这个收藏: {_id : "1", arrayProperty : ["1", "2"]} {_id : "2", arrayProperty : ["1", "4"]} {_id : "3", arrayProperty : ["1", "7", "8"]} {_id : "4", arrayPro

我有一个收藏,里面有这样的文件:

{
_id : "1",
arrayProperty : ["1","2","3"]
}
我想找到一些数组中包含所有arrayProperty元素的文档

假设我有这个收藏:

{_id : "1", arrayProperty : ["1", "2"]}
{_id : "2", arrayProperty : ["1", "4"]}
{_id : "3", arrayProperty : ["1", "7", "8"]}
{_id : "4", arrayProperty : ["1", "9"]}
我想找到所有arrayProperty元素都包含在
[“1”、“2”、“3”、“4”]

它应返回:

{_id : "1", arrayProperty : ["1", "2"]}
{_id : "2", arrayProperty : ["1", "4"]}

这里的基本概念是查找不在每个数组元素的可能值列表中的内容,然后“排除”该文档。这意味着对列表使用with并反转逻辑:

db.collection.find({ 
  "arrayProperty": { 
    "$not": { "$elemMatch": { "$nin": ["1", "2", "3", "4"] } } 
  }
})
返回正确的文档:

{ "_id" : "1", "arrayProperty" : [ "1", "2" ] }
{ "_id" : "2", "arrayProperty" : [ "1", "4" ] }
它实际上使用来计算表达式,而不是我们稍后将提到的via或。这是正确的结果,但这里唯一的问题是操作符模式实际上否定了任何索引的使用。幸运的是,我们可以采取一些措施:

db.collection.find({
  "arrayProperty": {
    "$in": ["1", "2", "3", "4"],
    "$not": { "$elemMatch": { "$nin": ["1", "2", "3", "4"] } }
  } 
})
虽然一开始看起来有点滑稽,但添加here是一个有效的条件。它对查询的作用是强制要求在选择有效文档时实际使用索引。在问题示例中,它仍然是所呈现文档的“全部”,但在现实世界中,并非所有内容都与参数列表相匹配

从本质上讲,它更改了以下解析的查询条件:

"winningPlan" : { "stage" : "COLLSCAN"
为此:

"winningPlan" : { "stage" : "FETCH",

"inputStage" : { "stage" : "IXSCAN",
这使得一个值得添加到表达式中的过滤器成为可能,“nativequeryoperator”表达式是实现这一点的最快方法

问题在于(除了只能从MongoDB 3.6中获得之外),它意味着需要扫描“整个集合”,以便应用它所包含的“聚合运算符表达式”。当然,我们还刚刚了解了添加到查询中的内容

db.collection.find({
   "arrayProperty": { "$in": ["1", "2", "3", "4"] },
   "$expr": { "$setIsSubset": ["$arrayProperty", ["1", "2", "3", "4"]] }
})
这有一个类似的
IXSCAN
输入,因为存在索引,并且仅使用布尔条件来拒绝在索引选择中找到的其他文档

早期MongoDB版本的使用形式不太理想:

db.collection.aggregate([
  { "$match": { "$in": ["1", "2", "3", "4"] } },
  { "$redact": {
    "if": { "$setIsSubset": ["$arrayProperty", ["1", "2", "3", "4"]] },
    "then": "$$KEEP",
    "else": "$$PRUNE"
  }}
])
或使用:

所以所有的工作实际上都完成了,但是和的组合,也包括索引选择的操作符,实际上是你真正想要的。所有版本都支持它

db.collection.find({
  "arrayProperty": { "$in": ["1", "2", "3", "4"] },
  "$where": function() {
    return this.arrayProperty.every(a => ["1", "2", "3", "4"].some(s => a === s))
  }
})