使用Mongoose Aggregation分组并计算平均值

时间:2015-10-23 17:22:02

标签: node.js mongodb mongoose aggregation-framework

我有一个具有以下结构的MongoDB集合:

    Prices: [ 
        exchange, symbol, volume, buy, sell, last, low, high
    ]

我使用Mongoose查询记录,我希望在过去3小时内按照符号分组获得买入,卖出,持续,低,高的平均值。

基本上我的目标是展示如下内容:         (设A,B,C,D,E,F为数字的占位符)

    Latest Prices for Exchange:
        Symbol A    Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
        Symbol B    Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B

    3 Hour Averages for Exchange:
        Symbol A:   Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
        Symbol B:   Volume: X   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B

我一直在阅读MongoDB文档: https://docs.mongodb.org/manual/reference/operator/aggregation/group/

为了获得平均值,我尝试过这样的事情:

    query = Prices.aggregate([
        {
            $group: {
                _id: "$symbol",
                avg_last: { $avg: "$last" },
                avg_buy: { $avg: "$buy" },
                avg_sell: { $avg: "$sell" },
                avg_low: { $avg: "$low" },
                avg_high: { $avg: "$high" },
                averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                count: { $sum: 1 }
            }
        }
    ]);

问题在于,没有“条件”将结果限制为过去3小时。

再次使用MongoDB文档获取$ cond https://docs.mongodb.org/manual/reference/operator/aggregation/cond/

我试图应用这个:

    var threeHoursAgo = new Date();
    threeHoursAgo.setHours(threeHoursAgo.getHours() - 3);

    query = Prices.aggregate([
        {
            $group: {
                _id: "$symbol",
                avg_last: { $avg: "$last" },
                avg_buy: { $avg: "$buy" },
                avg_sell: { $avg: "$sell" },
                avg_low: { $avg: "$low" },
                avg_high: { $avg: "$high" },
                averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                count: { $sum: 1 }
            },
            $cond: {
                exchange: strategy.primaryExchanges[i].exchange._id,
                timestamp: {
                    $gte: threeHoursAgo
                }
            }
        }
    ]);

但我收到以下错误:

"Error: Arguments must be aggregate pipline operators".

编辑:我也尝试使用$ match,如:

    query = Prices.aggregate([
        {
            $group: {
                _id: "$symbol",
                avg_last: { $avg: "$last" },
                avg_buy: { $avg: "$buy" },
                avg_sell: { $avg: "$sell" },
                avg_low: { $avg: "$low" },
                avg_high: { $avg: "$high" },
                averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                count: { $sum: 1 }
            }
        },
        {
            $match: {
                $and: [
                    {exchange: strategy.primaryExchanges[i].exchange._id},
                    {timestamp: {$gte: threeHoursAgo} }
                ]
            }
        }
    ]);

但我得到一个空数组。

编辑2 以下是我的价格集合中的示例文档:

 {"_id":"ObjectId(56296ac0603c75c80b3d581f)","symbol":"XBT24H","contract":"XBT24H","exchange":"ObjectId(55dc8ae9ecb73538125ddd9a)","timestamp":"ISODate(2015-10-22T23:01:15.000Z)","volume":260475,"buy":275.41,"sell":275.7,"low":274.44,"last":275.7,"high":277.03,"__v":0}

1 个答案:

答案 0 :(得分:2)

我已经找到了解决方案。

问题是我的$ match声明。必须在我的$ group声明之前

    query = Prices.aggregate([
        {
            $match: {
                $and: [
                    {exchange: strategy.primaryExchanges[i].exchange._id},
                    {timestamp: {$gte: threeHoursAgo} }
                ]
            }
        },
        {
            $group: {
                _id: "$symbol",
                avg_last: { $avg: "$last" },
                avg_buy: { $avg: "$buy" },
                avg_sell: { $avg: "$sell" },
                avg_low: { $avg: "$low" },
                avg_high: { $avg: "$high" },
                averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                count: { $sum: 1 }
            }
        }
    ]);

这可以工作并返回我期待的结果。