2016-04-07 11 views
2

我需要幫助才能從文檔中獲取具有最大字段(級別)值的數組元素。然後計算數組元素字段「bssid」分組的總髮生次數。如何將數組元素與聚合中的最大值進行匹配和組合

考慮以下數據

/* 1 */ 
{ 
    "_id" : "18:59:36:0c:94:a3", 
    "timestamp" : "1460012567", 
    "apdata" : [{ 
     "bssid" : "f4:b7:e2:56:e4:20", 
     "ssid" : "Test Network2", 
     "level" : -55 
    }, { 
     "bssid" : "b8:a3:86:67:03:56", 
     "ssid" : "Test Network1", 
     "level" : -76 
    }] 
} 
/* 2 */ 
{ 
    "_id" : "d0:b3:3f:b9:42:38", 
    "timestamp" : "1460013345", 
    "apdata" : [{ 
     "bssid" : "f4:b7:e2:56:e4:20", 
     "ssid" : "Test Network2", 
     "level" : -65 
    }, { 
     "bssid" : "b8:a3:86:67:03:56", 
     "ssid" : "Test Network1", 
     "level" : -46 
    }] 
} 
/* 3 */ 
{ 
    "_id" : "d0:b3:3f:b9:42:41", 
    "timestamp" : "1460013145", 
    "apdata" : [{ 
     "bssid" : "f4:b7:e2:56:e4:20", 
     "ssid" : "Test Network2", 
     "level" : -65 
    }, { 
     "bssid" : "b8:a3:86:67:03:56", 
     "ssid" : "Test Network1", 
     "level" : -46 
    }] 
} 

所需的輸出是

{ 
    "bssid" : "f4:b7:e2:56:e4:20", 
    "ssid" : "Test Network2", 
    "count" : 1 
}, { 
    "bssid" : "b8:a3:86:67:03:56", 
    "ssid" : "Test Network1", 
    "count" : 2 
} 

哪個是每個BSSID有每個文檔的在整個集合在陣列內的最大值的倍數。

+0

_id通常是一個唯一的標識符。你怎麼能通過它分組? –

+0

@JohnGreenall如果您遵循問題中的邏輯,它會要求對每個數組中僅有「兩個」的「appdata.bssid」值進行分組。問題的關鍵在於*「將特定網絡的層次數與所有文檔的最大值相比」*作爲與問題和數據相關的最佳短語。還有一個問題有一些值得注意的解決方法。 –

回答

1

如果你有MongoDB的3.2可用,那麼你可以做這樣的事情:

db.sample.aggregate([ 
    { "$project": { 
    "apdata": { 
     "$arrayElemAt": [ 
     { "$filter": { 
      "input": "$apdata", 
      "as": "el", 
      "cond": { 
      "$eq": [ 
       "$$el.level", 
       { "$max": { 
       "$map": { 
        "input": "$apdata", 
        "as": "data", 
        "in": "$$data.level" 
       } 
       }} 
      ] 
      } 
     }}, 
     0 
     ] 
    } 
    }}, 
    { "$group": { 
    "_id": "$apdata.bssid", 
    "ssid": { "$first": "$apdata.ssid" }, 
    "count": { "$sum": 1 } 
    }} 
]) 

至少對於MongoDB的2.6你需要這樣做:

db.sample.aggregate([ 
    { "$unwind": "$apdata" }, 
    { "$group": { 
    "_id": "$_id", 
    "apdata": { "$push": "$apdata" }, 
    "max": { "$max": "$apdata.level" } 
    }}, 
    { "$unwind": "$apdata" }, 
    { "$redact": { 
    "$cond": { 
     "if": { "$eq": [ "$apdata.level", "$max" ] }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }}, 
    { "$group": { 
    "_id": "$apdata.bssid", 
    "ssid": { "$first": "$apdata.ssid" }, 
    "count": { "$sum": 1 } 
    }} 
]) 

而且MongoDB的2.4或2.2這樣:

db.sample.aggregate([ 
    { "$unwind": "$apdata" }, 
    { "$group": { 
    "_id": "$_id", 
    "apdata": { "$push": "$apdata" }, 
    "max": { "$max": "$apdata.level" } 
    }}, 
    { "$unwind": "$apdata" }, 
    { "$project": { 
    "apdata": 1, 
    "isMax": { "$eq": [ "$apdata.level", "$max" ] } 
    }}, 
    { "$match": { "isMax": true } }, 
    { "$group": { 
    "_id": "$apdata.bssid", 
    "ssid": { "$first": "$apdata.ssid" }, 
    "count": { "$sum": 1 } 
    }} 
]) 

在所有情況下$max用於在第一個文檔中獲取每個文檔中數組的「最大」值,然後您可以使用它在「$group」中使用之前「過濾」數組內容。這種方法僅針對版本

MongoDB 3.2:允許$max直接在值的「數組」上工作。因此,$map用於獲取"level"值,並找出「最大值」實際上是多少。

然後​​可用於返回與「max」值相匹配的數組元素,最後使用$arrayElemAt作爲普通返回該「唯一」元素(在兩個可能的和「零」索引中)文件。

整個過程可以在$group做「唯一」,如果你基本上重複整個語句既_id,爲了得到$first"ssid"價值,但它更容易在$project寫分別展示了一下。

MongoDB 2.6:這缺乏發燒友操作員,最值得注意的是$max「直接」在陣列上工作的能力。值得注意的是需要$unwind陣列第一個,然後實際上$group只是在原始文件,只爲了得到「最大」的價值。

然後該過程確實需要您再次$unwind,因爲您將在稍後對數組中的元素進行分組,然後使用$redact來過濾內容。這是$match的「邏輯」形式,您可以直接將"level"與早期階段計算的「最大值」進行比較。因此,不是「最大」的元素被刪除。

MongoDB 2。4:又是基本相同的邏輯,除了代替$redact,你實際上需要物理$project才能在文檔中放置一個字段用於使用$match進行過濾。


所有版本都有相同的最終$group,在那裏你提供的路徑,"apdata.bssid"的分組鍵和$first結果爲"ssid"和簡單$sum該分組邊界上計算分組鍵的出現在結果。

一切只返回如下:

{ "_id" : "f4:b7:e2:56:e4:20", "ssid" : "Test Network2", "count" : 1 } 
{ "_id" : "b8:a3:86:67:03:56", "ssid" : "Test Network1", "count" : 2 } 

其實最 「有效」 的形式MongoDB的3.2將如下所示:

db.sample.aggregate([ 
    { "$group": { 
    "_id": { 
     "$arrayElemAt": [ 
     { "$map": { 
      "input": { 
      "$filter": { 
       "input": "$apdata", 
       "as": "el", 
       "cond": { 
       "$eq": [ 
        "$$el.level", 
        { "$max": { 
        "$map": { 
         "input": "$apdata", 
         "as": "data", 
         "in": "$$data.level" 
        } 
        }} 
       ] 
       } 
      }    
      }, 
      "as": "apdata", 
      "in": { 
      "bssid": "$$apdata.bssid", 
      "ssid": "$$apdata.ssid" 
      } 
     }}, 
     0 
     ] 
    }, 
    "count": { "$sum": 1 } 
    }} 
]) 

有了一個稍微不同的形式,由於化合物_id,但它只是一個單獨的$group階段,沒有重複整個過程來查找「最大」值的數組元素數據:

{ 
    "_id" : { 
     "bssid" : "b8:a3:86:67:03:56", 
     "ssid" : "Test Network1" 
    }, 
    "count" : 2 
    } 
    { 
    "_id" : { 
     "bssid" : "f4:b7:e2:56:e4:20", 
     "ssid" : "Test Network2" 
    }, 
    "count" : 1 
    } 
+0

感謝Neil Lunn ..它的作品和感謝詳細解釋。幫助Mongodb初學者 – rkd

相關問題