通过相对数组元素位置查找doc

时间:2016-04-06 17:01:01

标签: mongodb mongodb-query aggregation-framework

我想在数组中搜索一个字段,并想知道数组中该字段的索引是否可以找到它? 例如:

doc1: {id:123, hobby:['chess','cards','dance']}
doc2: {id:123, hobby:['cards','dance','chess']}

我想只搜索有的文件 chesscards,但只有chess之前card的{​​{1}}。所以在doc1

的情况下

2 个答案:

答案 0 :(得分:3)

您可以使用$where运算符执行此操作,将其与$all运算符耦合以保持合理的性能:

db.test.find({
  // Find all the docs where hobby contains both 'cards' and 'chess'
  hobby: {$all: ['cards', 'chess']},
  // Of those, run this $where query that evaluates the indexes of the matched elements
  $where: "this.hobby.indexOf('cards') > this.hobby.indexOf('chess')"
})

hobby上添加索引以获得最佳效果。

答案 1 :(得分:0)

为了获得最佳性能,您实际上将.aggregate()$match阶段一起用于“查询”,以缩小与包含$all数组中元素的文档的可能匹配,以及$redact从剩余结果中过滤:

db.test.aggregate([
  { "$match": { "hobby": { "$all": [ "chess", "cards" ] } } },
  { "$redact": {
    "$cond": {
      "if": {
        "$eq": [
          { "$filter": {
              "input": "$hobby",
              "as": "hobby",
              "cond": {
                "$or": [
                  { "$eq": [ "$$hobby", "chess" ] },
                  { "$eq": [ "$$hobby", "cards" ] }
                ]
              }
          }},
          ["chess","cards"]
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }     
  }}
])

有效的原因是因为$filter只能返回与此处给出的条件匹配的元素,并将它们以相同的顺序返回,其中它们存储在原始文件中文献。

一旦“过滤”下来,如果原始数组中的元素确实按此顺序排列,那么数组应该是内容["chess","cards"]完全匹配

请注意,尽管它“看起来”更简单,但您无法使用"set operators"来测试它,因为“sets”实际上并不被认为是有序的。

所以你需要维护顺序的东西,而$filter实际上是唯一能够以有效的方式对数组内容做到这一点的事情。因此,解决方案确实仅限于需要MongoDB 3.2或更高版本才能实际运行。

对于旧版本,请参阅answer from JohnnyHK使用$where对数组元素应用.indexOf()测试作为使用$all的附加过滤器。

但是如果你有MongoDB 3.2和可用的运算符,那么聚合框架可用的本机编码操作比$where的JavaScript评估运行得快得多,应该优先使用。