骨料

2013-02-20 99 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 
} 

不,你不能使用你的当前模式时,该字段不执行这个查询,因为$开卷失败一个数组字段。