骨料

2013-02-20 60 views
1

在收集抽象文件MD給出:骨料

{ 
    vals : [{ 
     uid : string, 
     val : string|array 
    }] 
} 

下文中,部分正確的聚合給出:

db.md.aggregate(
    { $unwind : "$vals" }, 
    { $match : { "vals.uid" : { $in : ["x", "y"] } } }, 
    { 
     $group : { 
      _id : { uid : "$vals.uid" }, 
      vals : { $addToSet : "$vals.val" } 

     } 
    } 
); 

,可能導致以下結果:

"result" : [ 
    { 
     "_id" : { 
      "uid" : "x" 
     }, 
     "vals" : [ 
      [ 
       "24ad52bc-c414-4349-8f3a-24fd5520428e", 
       "e29dec2f-57d2-43dc-818a-1a6a9ec1cc64" 
      ], 
      [ 
       "5879b7a4-b564-433e-9a3e-49998dd60b67", 
       "24ad52bc-c414-4349-8f3a-24fd5520428e" 
      ] 
     ] 
    }, 
    { 
     "_id" : { 
      "uid" : "y" 
     }, 
     "vals" : [ 
      "0da5fcaa-8d7e-428b-8a84-77c375acea2b", 
      "1721cc92-c4ee-4a19-9b2f-8247aa53cfe1", 
      "5ac71a9e-70bd-49d7-a596-d317b17e4491" 
     ] 
    } 
] 

as x是在包含數組的文檔上聚合的結果,而不是一個字符串,結果中的vals是一個數組數組。我在這種情況下尋找的是有一個平坦的數組(如y的結果)。

對我來說,它似乎是我想通過一個aggegration調用來實現,目前不支持任何給定的操作,例如,無法完成類型轉換,或者在每種情況下將數組展開爲輸入類型。

是地圖減少我唯一的選擇嗎?如果沒有...任何提示?

謝謝!

+1

最乾淨的解決辦法是返工您的架構,使'vals.val'是總是一個數組。然後這個(和其他許多事情)變得容易。 – JohnnyHK 2013-02-22 15:11:04

回答

3

您可以在不更改模式的情況下使用聚合執行所需的計算(儘管您可能會考慮更改模式以簡化此字段的查詢和聚合)。

爲了便於閱讀,我將流水線分成了多個步驟。爲了便於閱讀,我還簡化了文檔。

樣品輸入:

> db.md.find().pretty() 
{ 
    "_id" : ObjectId("512f65c6a31a92aae2a214a3"), 
    "uid" : "x", 
    "val" : "string" 
} 
{ 
    "_id" : ObjectId("512f65c6a31a92aae2a214a4"), 
    "uid" : "x", 
    "val" : "string" 
} 
{ 
    "_id" : ObjectId("512f65c6a31a92aae2a214a5"), 
    "uid" : "y", 
    "val" : "string2" 
} 
{ 
    "_id" : ObjectId("512f65e8a31a92aae2a214a6"), 
    "uid" : "y", 
    "val" : [ 
     "string3", 
     "string4" 
    ] 
} 
{ 
    "_id" : ObjectId("512f65e8a31a92aae2a214a7"), 
    "uid" : "z", 
    "val" : [ 
     "string" 
    ] 
} 
{ 
    "_id" : ObjectId("512f65e8a31a92aae2a214a8"), 
    "uid" : "y", 
    "val" : [ 
     "string1", 
     "string2" 
    ] 
} 

流水線階段:

> project1 = { 
    "$project" : { 
     "uid" : 1, 
     "val" : 1, 
     "isArray" : { 
      "$cond" : [ 
       { 
        "$eq" : [ 
         "$val.0", 
         [ ] 
        ] 
       }, 
       true, 
       false 
      ] 
     } 
    } 
} 
> project2 = { 
    "$project" : { 
     "uid" : 1, 
     "valA" : { 
      "$cond" : [ 
       "$isArray", 
       "$val", 
       [ 
        null 
       ] 
      ] 
     }, 
     "valS" : { 
      "$cond" : [ 
       "$isArray", 
       null, 
       "$val" 
      ] 
     }, 
     "isArray" : 1 
    } 
} 
> unwind = { "$unwind" : "$valA" } 
> project3 = { 
    "$project" : { 
     "_id" : 0, 
     "uid" : 1, 
     "val" : { 
      "$cond" : [ 
       "$isArray", 
       "$valA", 
       "$valS" 
      ] 
     } 
    } 
} 

最終聚集:

> db.md.aggregate(project1, project2, unwind, project3, group) 
{ 
    "result" : [ 
     { 
      "_id" : "z", 
      "vals" : [ 
       "string" 
      ] 
     }, 
     { 
      "_id" : "y", 
      "vals" : [ 
       "string1", 
       "string4", 
       "string3", 
       "string2" 
      ] 
     }, 
     { 
      "_id" : "x", 
      "vals" : [ 
       "string" 
      ] 
     } 
    ], 
    "ok" : 1 
} 
+0

令人印象深刻!必須在接下來的20個小時內檢查。 – 2013-02-28 14:48:46

+0

這甚至不是最長也不是最痛苦的管道我發佈到SO :) – 2013-02-28 14:49:25

+0

這是有點類似(但不同的列不是類型)http://stackoverflow.com/questions/13521259/combining-columns-into-one- in-mongodb-aggregate-framework – 2013-02-28 14:55:22

0

如果你總是使用「vals.val」域作爲一個陣列場(即使當記錄只包含一個元素)你可以按如下做很容易修改您的模式:

db.test_col.insert({ 
    vals : [ 
     { 
      uid : "uuid1", 
      val : ["value1"] 
     }, 
     { 
      uid : "uuid2", 
      val : ["value2", "value3"] 
     }] 
    }); 
db.test_col.insert(
    { 
     vals : [{ 
      uid : "uuid2", 
      val : ["value4", "value5"] 
     }] 
    }); 

使用這種方法你只需要使用兩個$ unwind操作:一個展開「父」數組,第二個展開每個「vals.val」值。所以,像查詢

db.test_col.aggregate(
    { $unwind : "$vals" }, 
    { $unwind : "$vals.val" }, 
    { 
     $group : { 
      _id : { uid : "$vals.uid" }, 
      vals : { $addToSet : "$vals.val" } 
     } 
    } 
); 

你可以得到你的期望值:

{ 
    "result" : [ 
     { 
      "_id" : { 
       "uid" : "uuid2" 
      }, 
      "vals" : [ 
       "value5", 
       "value4", 
       "value3", 
       "value2" 
      ] 
     }, 
     { 
      "_id" : { 
       "uid" : "uuid1" 
      }, 
      "vals" : [ 
       "value1" 
      ] 
     } 
    ], 
    "ok" : 1 
} 

不,你不能使用你的當前模式時,該字段不執行這個查詢,因爲$開卷失敗一個數組字段。