2015-10-13 25 views
4

n次我有一个MongoDB的集合world在以下格式的文档:如何查询文件,其中阵列有一个字段超过MongoDB中

{ 
    _id : ObjectId("4e8ae86d08101908e1000001"), 
    country : [ 
     { 
      state: "Newyork", 
      type: 1 
     }, 
     { 
      state: "California", 
      type: 1 
     }, 
     { 
      state: "Texas", 
      type: 2 
     } 
    ] 
} 

我们可以很容易地得到具有文档四在arrary更指出:

db.world.find({'country.4': {$exists: true} }) 

但我怎么能得到的文件,其中具有type: 1四个或更多状态的国阵?

此外,我想在查询中避免$where运算符。

编辑1

回答布雷克七权似乎对我,但是当我尝试做反向即;得到的文件与超过n区,然后我得到错误的结果:

下面是该查询:

db.world.aggregate([ 
    { "$redact": { 
     "$cond": { 
      "if": { 
       "$lte": [ 
        { "$size": { "$setDifference": [ 
         { "$map": { 
          "input": "$country", 
          "as": "el", 
          "in": { 
           "$cond": { 
            "if": { "$eq": [ "$$el.type", 769 ] }, 
            "then": "$$el", 
            "else": false 
           } 
          } 
         }}, 
         [false] 
        ]}}, 
        4 
       ] 
      }, 
      "then": "$$KEEP", 
      "else": "$$PRUNE" 
     } 
    }} 
]); 

回答

3

底线是,你需要过滤掉非比赛和“数“匹配的发生是为了确定文件是否符合您的条件。这可以通过滤波器阵列上的$size运算符完成,作为$redact的逻辑测试的一部分。

其他地方提出的$setIsSubset的建议无法正常工作,因为“设置”基本上会取消任何重复的项目。这意味着任何匹配将降低到:

"$setIsSubset": [[1,0],[1]] 

这当然是false条件。这是因为大多数情况下阵列成员不匹配(因此产生0),并且每个“集合”有效地减少为“独特”成员。甚至当“所有”成员进行匹配然后将结果减少到这一点:

"$setIsSubset": [[1],[1]] 

其中而正赛,这使得完全没有断言匹配所需的“数字”实际上是满足。

所以只要阵列成员本身实际上是“独一无二的”,那么你就可以,而采取这种方法来筛选和计数比赛:

db.world.aggregate([ 
    { "$match": { "country.3": { "$exists": true } }}, 
    { "$redact": { 
     "$cond": { 
      "if": { 
       "$gte": [ 
        { "$size": { "$setDifference": [ 
         { "$map": { 
          "input": "$country", 
          "as": "el", 
          "in": { 
           "$cond": { 
            "if": { "$eq": [ "$$el.type", 1 ] }, 
            "then": "$$el", 
            "else": false 
           } 
          } 
         }}, 
         [false] 
        ]}}, 
        4 
       ] 
      }, 
      "then": "$$KEEP", 
      "else": "$$PRUNE" 
     } 
    }} 
]) 

所以全部退回元素的“设置”比较$setDifference以过滤出返回的任何false值。然后测试没有匹配的结果数组,然后测试$size以查看是否满足必要的匹配,并且通过$$PRUNE丢弃文档,但是他们没有。

当然$map这里做的处理每个元素或者返回原始元素整体或交替地false在条件不满足的地方。

如果实际上在数组中有重复的信息,说明数组很重要,那么未来的MongoDB版本将具有$filter,这两个过程都简化了一些过程,最重要的是不会在删除重复项时删除重复项“设置”:

db.world.aggregate([ 
    { "$match": { "country.3": { "$exists": true } }}, 
    { "$redact": { 
     "$cond": { 
      "if": { 
       "$gte": [ 
        { "$size": { "$filter": { 
         "input": "$country", 
         "as": "el", 
         "cond": { 
          "$eq": [ "$$el.type", 1 ] 
         } 
        }}}, 
        4 
       ] 
      }, 
      "then": "$$KEEP", 
      "else": "$$PRUNE" 
     } 
    }} 
]) 

不过,当然,直到该版本可用,则需要使用$unwind$match,同时保持重复过滤数组,然后通过$group首先获得了“数” a更传统的方法:

db.world.aggregate([ 
    { "$match": { "country.3": { "$exists": true } }}, 
    { "$project": { "country": 1, "countryCopy": "$country" } }, 
    { "$unwind": "$country" }, 
    { "$match": { "country.type": 1 } }, 
    { "$group": { 
     "_id": "$_id", 
     "country": { "$first": "$countryCopy" } 
     "count": { "$sum": 1 } 
    }}, 
    { "$match": { "count": { "$gte": 4 } }} 
]) 

但希望你没有在数组中重复,所以没关系。

同样重要的通过测试的最小指数至少存在并且从与小于4正在处理废弃的文档以使用初始$match立即过滤掉阵列没有所需数量的元件以可能匹配(数组索引n-1)在这种情况下总共是元素。

这是$exists测试,在这里很有用。这减少了在稍后的处理中匹配文档,由于没有足够的元素开始而不能满足所需的匹配计数。

相关问题