查询数组以包含范围内的“仅”元素

时间:2018-05-28 03:36:42

标签: mongodb mongodb-query

假设我有以下文件。

{ "_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 ] }

1 个答案:

答案 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()的其他方法都不能实际查看“索引”以满足条件。它们仅在所有情况下用作“附加过滤器”,通过最终结果中的“范围”从中“排除”任何“潜在”匹配文档。