2015-10-13 54 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測試,在這裏很有用。這減少了在稍後的處理中匹配文檔,由於沒有足夠的元素開始而不能滿足所需的匹配計數。

相關問題