2017-10-20 145 views
3
集團

在我查詢我想_id 這裏同一項目合併成一個字符串組是我的文檔的毗連字符串由

"_id" : ObjectId("59e955e633d64c81875bfd2f"), 
"tag_id" : 1, 
"client_id" : "10001" 



"_id" : ObjectId("59e955e633d64c81875bfd30"), 
"tag_id" : 1, 
"client_id" : "10002" 

我希望輸出將

"_id" : 1 
"client_id" : "10001,10002" 
+0

對於錯字感到抱歉,它應該按tag_id – shiyiwan

+0

@HassanImam分組幾乎沒有重複。這個問題特別要求「concat string」,這當然不是你所建議的副本顯示的東西。 –

+0

@NeilLunn我注意到它並刪除了評論。 –

回答

1

你可以做它將聚合框架作爲「兩步」操作。這是通過$push先積累的項目到數組withing一個$group管道,然後用$reduce使用$concat在最終投射所產生的陣列上:

db.collection.aggregate([ 
    { "$group": { 
    "_id": "$tag_id", 
    "client_id": { "$push": "$client_id" } 
    }}, 
    { "$addFields": { 
    "client_id": { 
     "$reduce": { 
     "input": "$client_id", 
     "initialValue": "", 
     "in": { 
      "$cond": { 
      "if": { "$eq": [ "$$value", "" ] }, 
      "then": "$$this", 
      "else": { 
       "$concat": ["$$value", ",", "$$this"] 
      } 
      } 
     } 
     } 
    } 
    }} 
]) 

我們也適用$cond這裏避免連接一個空字符串結果中帶有逗號,因此它看起來更像是一個分隔列表。

FYI有一個JIRA問題SERVER-29339它不要求$reduce被實現爲accumulator expression,允許它在$group流水線階段直接使用。不太可能很快發生,但理論上它將取代上述中的$push,並使操作成爲單一管線階段。示例建議的語法在JIRA問題上。

如果沒有$reduce做(需要的MongoDB 3.4),那麼剛剛發佈過程中的光標:

db.collection.aggregate([ 
    { "$group": { 
    "_id": "$tag_id", 
    "client_id": { "$push": "$client_id" } 
    }}, 
]).map(doc => 
    Object.assign(
    doc, 
    { "client_id": doc.client_id.join(",") } 
) 
) 

然後導致這樣使用mapReduce的其他選擇,如果你真的必須:

db.collection.mapReduce(
    function() { 
    emit(this.tag_id,this.client_id); 
    }, 
    function(key,values) { 
    return [].concat.apply([],values.map(v => v.split(","))).join(","); 
    }, 
    { "out": { "inline": 1 } } 
) 

當然哪個輸出mapReduce形式的_idvalue作爲鍵集,但它基本上是輸出。

我們使用[].concat.apply([],values.map(...)),因爲「減速器」的輸出可以是「分隔字符串」,因爲mapReduce增量式工作,結果很大,因此減速器的輸出可以在另一次傳遞時變成「輸入」。所以我們需要期待這可以發生並相應地對待它。

+0

謝謝,這真的很有用,我用mongo 3.4,因此第一個腳本完美地工作。 – shiyiwan