MongoDB聚合对象数组
Posted
技术标签:
【中文标题】MongoDB聚合对象数组【英文标题】:MongoDB Aggregate Array of Objects 【发布时间】:2021-06-21 05:24:57 【问题描述】:我有许多名为“项目”的文件,格式如下:
Item =
"_id" : ObjectId("6059f025fb8378a294180cc3"),
"name" : "My Name",
"category" : "My Category",
"marketData" :
"currency" : "€",
"history" : [
"timestamp" : 1,
"price" : 1.1,
"volume" : 10
,
"timestamp" : 3,
"price" : 2.2,
"volume" : 20
,
]
历史长度不同,每个文档都有不同的时间戳,有些文档会共享几个时间戳。
我需要每个类别的每个时间戳的价格和数量的总和。 像这样:
Categories =
[
"_id",
"name": "My Category",
"marketData":
"currency": "€",
"history": [
"timestamp": 1,
"price": "sum of prices of all items at timestamp 1",
"volume": "sum of volume of all items at timestamp 1"
,
...
]
,
...
]
我已经试过了,但上面写着SyntaxError: invalid property id
db.items.aggregate([
$unwind: "$marketData.history" ,
$group:
_id: "$marketData.history.timestamp",
price: $sum:"$marketData.history.price"
,
$group:
_id:null,
price:
$push: timestamp: "$timestamp", price:"$price"
,
$project:
marketData.history:1,
_id:0
])
【问题讨论】:
您期望的输出格式是什么?你的 MongoDB 版本是多少? 【参考方案1】:解决方案 1:如果您只想对数据进行分组。
db.items.aggregate([
$unwind: "$marketData.history" ,
$group:
_id:
category: "$category",
timestamp: "$marketData.history.timestamp"
,
price: $sum: "$marketData.history.price" ,
volume: $sum: "$marketData.history.volume"
,
$project:
_id: 0,
category: "$_id.category",
timestamp: "$_id.timestamp",
price: "$price",
volume: "$volume"
,
$group:
_id: null,
result: $push: "$$ROOT"
]);
解决方案 2:与您的预期输出完全匹配。
db.items.aggregate([
$unwind: "$marketData.history" ,
$group:
_id:
category: "$category",
timestamp: "$marketData.history.timestamp"
,
name: $first: "$name" ,
currency: $first: "$marketData.currency" ,
price: $sum: "$marketData.history.price" ,
volume: $sum: "$marketData.history.volume"
,
$sort: "_id.timestamp": 1
,
$group:
_id: "$_id.category",
category: $first: "$_id.category" ,
name: $first: "$name" ,
currency: $first: "$currency" ,
history:
$push:
timestamp: "$_id.timestamp",
price: "$price",
volume: "$volume"
,
$addFields:
marketData:
currency: "$currency",
history: "$history"
,
currency: "$$REMOVE",
history: "$$REMOVE"
]);
输出:
/* 1 */
"_id" : "My Category",
"category" : "My Category",
"name" : "My Name",
"marketData" :
"currency" : "€",
"history" : [
"timestamp" : 1,
"price" : 10,
"volume" : 20
,
"timestamp" : 3,
"price" : 2.2,
"volume" : 20
]
,
/* 2 */
"_id" : "My Category 2",
"category" : "My Category 2",
"name" : "My Name 2",
"marketData" :
"currency" : "€",
"history" : [
"timestamp" : 1,
"price" : 1.1,
"volume" : 10
,
"timestamp" : 3,
"price" : 2.2,
"volume" : 20
]
您也收到了该错误,因为有一个额外的关闭 大括号,并且
marketData.history
未包含为 "marketData.history"
。检查以下更正后的查询:
db.items.aggregate([
$unwind: "$marketData.history" ,
$group:
_id: "$marketData.history.timestamp",
price: $sum: "$marketData.history.price"
,
$group:
_id: null,
price:
$push: timestamp: "$_id", price: "$price"
,
$project: _id: 0
])
【讨论】:
它返回了一个包含所有项目组合的 timestamp, priceSum, volumeSum 数组。但是我该如何对它们进行分类呢?我需要为 Items 的每个类别提供 timestamp, priceSum, volumeSum 添加预期的输出格式。将更新答案。 这是我问题中的第二个问题 检查 SOLUTION 2 以完全匹配您的预期输出。 我尝试使用 javascript 代码将其转换为准确的格式,但是当我完成后,您更新了您的解决方案,并且您的方式更好。我唯一需要更改的是第一个 $groupname: $first: "$name"
必须是 name: $first: "$category"
因为 Item 也有名称,类别名称是类别属性。我尝试在 $unwind 之后使用 $sort: "marketData.history.timestamp": 1,
按升序对时间戳进行排序,但它不起作用。以上是关于MongoDB聚合对象数组的主要内容,如果未能解决你的问题,请参考以下文章