2012-10-24 69 views
7

是否可以使用聚合框架按数组的特定元素进行分组?按mongo聚合框架排列的数组特定元素

使得具有这样的文件:

{ 
    name: 'Russell', 
    favourite_foods: [ 
    { name: 'Pizza', type: 'Four Cheeses' }, 
    { name: 'Burger', type: 'Veggie'} 
    ], 
    height: 6 
} 

我能得到的最高爱吃的食物独特的名单(即索引0食物。)与最高的人的身高是谁的顶部最喜欢的食物是沿?

像这样的东西(虽然它不作为数组索引访问点符号的工作似乎并没有在聚合框架工作):

db.people.aggregate([ 
    { $group : { _id: "$favourite_foods.0.name", max_height: { $max : "$height" } } } 
]) 

回答

5

看起来它是目前无法提取从阵列中聚集特定的元素: https://jira.mongodb.org/browse/SERVER-4589

+0

是的,我发现了。我有点希望有人提出了一个解决方法... – Russell

+0

你不能提取位置的任意元素,你碰巧有办法通过$ unwind获取第一个或最后一个元素,并用$ first或$ last操作符重新获得$ group。 –

+1

**好消息**:该问题最终通过[arrayElementAt运算符](https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/) – joeytwiddle

2

我想你可以使用$项目和$放松运营商(让我知道如果这是你要完成不算什么):

> db.people.aggregate(
    {$unwind: "$favourite_foods"}, 
    {$project: {food : "$favourite_foods", height: 1}}, 
    {$group : { _id: "$food", max_height: { $max : "$height" } } }) 


{ 
    "result" : [ 
     { 
      "_id" : { 
       "name" : "Burger", 
       "type" : "Veggie" 
      }, 
      "max_height" : 6 
     }, 
     { 
      "_id" : { 
       "name" : "Pizza", 
       "type" : "Four Cheeses" 
      }, 
      "max_height" : 6 
     } 
    ], 
    "ok" : 1 
} 

http://docs.mongodb.org/manual/applications/aggregation/

+0

解决,它将包括所有最喜欢的食物名单,不只是顶级的...汉堡不是任何人在这个非常小的数据集的首选:) –

+0

@asya是正确的,我只想要第一个食物从阵列 – Russell

+0

doh。我的错。好的,Asya。 – Jenna

14

好像你是依靠每个人的首选阵列中最喜欢的食物。如果是这样,那么您可以利用一个聚合框架运算符。

这里是管道可以使用:

db.people.aggregate(
[ 
    { 
     "$unwind" : "$favourite_foods" 
    }, 
    { 
     "$group" : { 
      "_id" : { 
       "name" : "$name", 
       "height" : "$height" 
      }, 
      "faveFood" : { 
       "$first" : "$favourite_foods" 
      } 
     } 
    }, 
    { 
     "$group" : { 
      "_id" : "$faveFood.name", 
      "height" : { 
       "$max" : "$_id.height" 
      } 
     } 
    } 
]) 

这个样本数据集:

> db.people.find().pretty() 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6 
} 
{ 
    "_id" : ObjectId("5088950bd4197aa2b9490742"), 
    "name" : "Lucy", 
    "favourite_foods" : [ 
     { 
      "name" : "Pasta", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 5.5 
} 
{ 
    "_id" : ObjectId("5088951dd4197aa2b9490743"), 
    "name" : "Landy", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Pizza", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 5 
} 
{ 
    "_id" : ObjectId("50889541d4197aa2b9490744"), 
    "name" : "Augie", 
    "favourite_foods" : [ 
     { 
      "name" : "Sushi", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Pizza", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6.2 
} 

你得到这些结果:

{ 
    "result" : [ 
     { 
      "_id" : "Pasta", 
      "height" : 5.5 
     }, 
     { 
      "_id" : "Pizza", 
      "height" : 6 
     }, 
     { 
      "_id" : "Sushi", 
      "height" : 6.2 
     } 
    ], 
    "ok" : 1 
} 
+0

如果名称不唯一,则可以在第一个$组中使用_id。 –

+0

不错的解决方案,但它依赖于展开的文档保留它们的排序顺序 - 你能依靠这个吗?它是否被记录在某处? – Russell

+0

我知道它是如何从多个试验中工作的,尽管它不在文档中,但我确实看过源代码,它似乎就是这种情况。请参阅:https://github.com/mongodb/mongo/blob/master/src/mongo/db/pipeline/document_source_unwind.cpp –

0

只需添加有关的更多信息使用后的结果"$wind"


文献:

> db.people.find().pretty() 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : [ 
     { 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
     }, 
     { 
      "name" : "Burger", 
      "type" : "Veggie" 
     } 
    ], 
    "height" : 6 
}, 
... 


AGGREAGATION:

db.people.aggregate([{ 
    $unwind: "$favourite_foods" 
}]); 


结果:

{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" :{ 
      "name" : "Pizza", 
      "type" : "Four Cheeses" 
    }, 
    "height" : 6 
}, 
{ 
    "_id" : ObjectId("508894efd4197aa2b9490741"), 
    "name" : "Russell", 
    "favourite_foods" : { 
      "name" : "Burger", 
      "type" : "Veggie" 
    }, 
    "height" : 6 
} 


另外:
如果有一个收集记录, 两个以上的阵列领域,我们可以使用"$project"阶段指定数组字段。

db.people.aggregate([ 
    { 
     $project:{ 
      "favourite_foods": 1 
     } 
    }, 
    { 
     $unwind: "$favourite_foods" 
    } 
]);