计算不同的子文档字段和输出为命名键

时间:2017-09-05 03:10:56

标签: mongodb aggregation-framework

在MongoDB中,如果我有一个如下所示的集合,

{
    "auctionId" : 22,
    "startDt" : "2017-08-28T06:00:00.000Z",
    "endDt" : "2017-09-04T06:00:00.000Z",
    "status" : "Open",
    "pickupDt" : "2017-09-07T06:00:00.000Z",
    "itmLst" : 
    [ 
        {
            "itemId" : 1,
            "location" : "Open",
            "currentBid" : 13.0,
            "highBidder" : 1897,
            "bidCnt" : 4,
            "catgegory" : "ANTIQUES"
             ...

如何使用聚合函数查询它以检索auctionId = 22的不同类别的计数,按itmLststategory进行分组,因此它将返回如下所示的结果集:

{
    "ANTIQUES": 56,
    "TOOLS": 89,
    "JEWLRY": 45,
    ...
}

2 个答案:

答案 0 :(得分:1)

此处的基本情况是将.aggregate()$unwind一起使用,因为您需要访问数组中的值作为分组键,当然还需$group,因为这就是您的方式&# 34;组"事情:

db.collection.aggregate([
  { "$match": { "auctionId": 22 } },
  { "$unwind": "$itmLst" },
  { "$group": {
    "_id": "$itmLst.category",
    "count": { "$sum": 1 }
  }}
])

这将为您提供如下输出:

{ "_id": "ANTIQUES", "count": 56 }
{ "_id": "TOOLS", "count": 89 }
{ "_id": "JEWLRY", "count":  45 }

现在你真的应该学会与之共存,因为"列表"在默认的游标格式中是一件很好的事情,它是自然可迭代的。此外,恕我直言的命名键自然不适合数据表示,你通常需要一个可迭代列表中的公共属性。

如果你真的打算使用单数命名密钥输出,那么你要么需要MongoDB 3.4.4或更高版本才能访问$arrayToObject,这将允许你使用这些值作为名称键,当然还有$replaceRoot,以便将该表达式输出用作要生成的新文档:

db.collection.aggregate([
  { "$match": { "auctionId": 22 } },
  { "$unwind": "$itmLst" },
  { "$group": {
    "_id": "$itmLst.category",
    "count": { "$sum": 1 }
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$count" } }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
])

或者,如果您没有该选项,那么您应该在代码中转换游标输出:

db.collection.aggregate([
  { "$match": { "auctionId": 22 } },
  { "$unwind": "$itmLst" },
  { "$group": {
    "_id": "$itmLst.category",
    "count": { "$sum": 1 }
  }}
]).toArray().reduce((acc,curr) => 
  Object.assign(acc,{ [curr._id]: curr.count }),
  {}
)

两者都合并为具有来自原始聚合输出的命名键的单个对象:

{
    "ANTIQUES": 56,
    "TOOLS": 89,
    "JEWLRY": 45,
    ...
}

这表明原始输出结果确实足够了,通常你想要那种"最终重塑"要在使用光标输出的代码中完成,如果你真的甚至需要重新整形,因为无论如何都返回了所需的基本数据。

答案 1 :(得分:0)

我找到了我正在寻找的答案。这个查询:

db.auctions.aggregate([
   { "$match": { "auctionId": 22 } },
   { $unwind:'$itmLst' }, 
   { $group:{_id:'$itmLst.catgegory', freq:{$sum:1}} },
   { $sort:{ "_id": 1 } }
]);

db.auctions.aggregate([ { "$match": { "auctionId": 22 } }, { $unwind:'$itmLst' }, { $group:{_id:'$itmLst.catgegory', freq:{$sum:1}} }, { $sort:{ "_id": 1 } } ]);

返回:

{
    "_id" : "ANTIQUES",
    "freq" : 9.0
}
{
    "_id" : "APPLIANCES",
    "freq" : 1.0
}
{
    "_id" : "ARTS CRAFTS",
    "freq" : 9.0
}
{
    "_id" : "BOOKS MAGAZINES",
    "freq" : 6.0
}

感谢Neil指出我正确的方向。