【问题标题】:MongoDB Aggregate Array of ObjectsMongoDB聚合对象数组
【发布时间】: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 版本是多少?

标签: mongodb mongoose aggregate


【解决方案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 代码将其转换为准确的格式,但是当我完成后,您更新了您的解决方案,并且您的方式更好。我唯一需要更改的是第一个 $group name: { $first: "$name" } 必须是 name: { $first: "$category" } 因为 Item 也有名称,类别名称是类别属性。我尝试在 $unwind 之后使用 { $sort: {"marketData.history.timestamp": 1}}, 按升序对时间戳进行排序,但它不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-14
  • 2020-07-27
  • 1970-01-01
  • 2020-08-20
  • 2020-07-02
  • 1970-01-01
  • 2018-04-20
相关资源
最近更新 更多