在mongoDB聚合框架中组合组和项目

时间:2016-05-31 14:52:26

标签: mongodb aggregation-framework

我的文档如下:

{ 
  "_id" : ObjectId("5748d1e2498ea908d588b65e"), 
  "some_item" : {
    "_id" : ObjectId("5693afb1b49eb7d5ed97de14"), 
    "item_property_1" : 1.0, 
    "item_property_2" : 2.0,
  }, 
  "timestamp" : "2016-05-28",  
  "price_information" : {
    "arbitrary_value" : 111, 
    "hourly_rates" : [
        {
            "price" : 74.45, 
            "hour" : "0"
        }, 
        {
            "price" : 74.45, 
            "hour" : "1"
        }, 
        {
            "price" : 74.45, 
            "hour" : "2"
        }, 
    ]
  }
}

我通过以下方式平均每天的价格:

db.hourly.aggregate([
  {$match: {timestamp : "2016-05-28"}},
  {$unwind: "$price_information.hourly_rates"},
  {$group: { _id: "$unique_item_identifier", total_price: { $avg: "$price_information.hourly_rates.price"}}}
]);

我正在努力在结果集中引入(投射)其他参数。我希望在结果集中也有some_itemtimestamp。我尝试在查询中使用$project: {some_item: 1, total_price: 1, ...},但这不对。

我想要的输出就像:

{ 
  "_id" : ObjectId("5693afb1b49eb7d5ed97de27"), 
  "someItem" : {
    "_id" : ObjectId("5693afb1b49eb7d5ed97de14"), 
    "item_property_1" : 1.0, 
    "item_property_2" : 2.0,
  }, 
  "timestamp" : "2016-05-28",  
  "price_information" : {
    "avg_price": 34
  }
}

如果有人可以给我一个提示,如何将分组和其他参数投射到结果集中,我会很感激。

最佳

罗布

1 个答案:

答案 0 :(得分:6)

如果使用MongoDB 3.2及更高版本,您可以在 $avg 管道中使用 $project ,因为它会返回指定表达式的平均值或每个文件的表达列表,例如

db.hourly.aggregate([
    { "$match": { "timestamp": "2016-05-28" } },
    {
        "$project": { 
            "price_information": { 
                "avg_price": { "$avg": "$price_information.hourly_rates.price" }
            },
            "someItem": 1,
            "timestamp": 1,
        }
    }
]);

在早期版本的MongoDB中, $avg 仅在 $group 阶段提供。要包含其他字段,请在分组中使用 $first 运算符:

db.hourly.aggregate([
    { "$match": { "timestamp": "2016-05-28" } },
    { "$unwind": "$price_information.hourly_rates" },
    {
        "$group": { 
            "_id": "$_id", 
            "avg_price": { "$avg": "$price_information.hourly_rates.price" },
            "someItem": { "$first": "$some_item" },
            "timestamp": { "$first": "$timestamp" },
        }
    },
    {
        "$project": {
            "price_information": { "avg_price": "$avg_price" },
            "someItem": 1
            "timestamp": 1
        }
    }
]);

注意 $first 阶段中 $group 运算符的使用在很大程度上取决于文档的方式进入该管道以及按组排序。由于 $first 将返回按键共享相同组的一组文档中的第一个文档值,因此 $group 阶段逻辑上应位于 $sort 阶段,以定义的顺序输入文档。只有在知道正在处理数据的顺序时才使用它。

但是,由于上面是主文档的_id键分组, $first 运算符应用于非非规范化字段(而不是展平{{1} }} array fields)将保证结果中的原始值。因此,不需要预先排序阶段来定义订单,因为在这种情况下不需要。