【问题标题】:How to aggregate a collection and find min/max values如何聚合集合并找到最小值/最大值
【发布时间】:2017-06-26 16:27:34
【问题描述】:

我有一个这样的“订单”集合:

{ typeID: 1, buyOrder: true, price: 100 },
{ typeID: 1, buyOrder: false, price: 120 },
{ typeID: 1, buyOrder: false, price: 130 },
{ typeID: 1, buyOrder: false, price: 250 },
{ typeID: 2, buyOrder: true, price: 500 },
{ typeID: 2, buyOrder: false, price: 610 },
{ typeID: 2, buyOrder: false, price: 690 },
{ typeID: 2, buyOrder: false, price: 590 }

我想汇总这个集合并找到每个 typeid 的最佳买入/卖出价格。

结果应该是:

{ typeID: 1, bestBuy: 100, bestSell: 120 }
{ typeID: 2, bestBuy: 500, bestSell: 610 }

定义 bestBuy / bestSell

bestBuy  = (buyOrder = true && max price)
bestSell = (buyOrder = false && min price)

这是我目前所拥有的,但我知道这是错误的。有任何想法吗 ?

db.orders.aggregate([
    { $sort : { typeID : 1 }},
    { $group: 
        { _id: { typeID : "$typeID", buyOrder : "$buyOrder"},
        price: { $max: "$price" },
        }
     },
     { $project:
         { _id: 0,
             typeID: "$_id.typeID",
             price: "$price",
             buyOrder: "$_id.buyOrder",
         }
     }
    ])

感谢您的宝贵时间。

【问题讨论】:

  • 你如何定义 bestBuy 和 bestSell?
  • 忘了说。 bestBuy = (buyOrder = true && max price)bestSell = (buyOrder = false && min price)
  • inmongodb.net/2015/11/… 你会得到最好的聚合框架参考

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您可能还不知道 $cond 运算符作为三元条件工作。因此,基本上,如果给定 a 作为第一个参数的条件是 true,则使用下一个参数中的值。如果条件计算结果为 false,则使用运算符中最后一个条件中的值。

事实证明这是完美的,因为您已经有了判断字段的真假指标

db.orders.aggregate([
    { "$project": {
        "typeID": 1,
        "bestBuy": { "$cond": [
            "$buyOrder",
            "$price",
            null
        ]},
        "bestSell": { "$cond": [
            "$buyOrder",
            null,
            "$price"
        ]}
    }},
    { "$group": {
        "_id": "$typeID",
        "bestBuy": { "$max": "$bestBuy" },
        "bestSell": { "$min": "$bestSell" }
    }},
    { "$sort": { "_id": 1 } }
])

所以这里使用$max$min可以否定不满足条件的结果中的null值。

【讨论】:

  • 这是完美的。我不知道$cond!非常感谢! :)
【解决方案2】:

也许使用 mapreduce,您可以通过类似的方式实现这一点:

var mapFunction1 = function() {
 emit(this.typeID , this.buyOrder, this.price);
};

var reduceFunction1 = function(key, values) {
 reducedValue = { bestBuy: 0, bestSell: 0 };
 for (var idx = 0; idx < values.length; idx++) {
  if(values[idx].buyOrder && reducedValue.bestBuy < values[idx].price) {
   reducedValue.bestBuy = values[idx].price
  }
  if(!values[idx].buyOrder && reducedValue.bestSell > values[idx].price) {
   reducedValue.bestSell = values[idx].price
  }
 }
 return reducedValue;
};

db.orders.mapReduce(
 mapFunction1,
 reduceFunction1,
 { out: "your_result" }
)

希望对你有帮助

【讨论】:

  • 你真的应该学习aggregation framework。除了本机代码方法的运行速度将比mapReduce 快得多这一事实之外,这个答案还有一个普遍的缺陷,即处理“大型”数组将付出相当大的成本。有更有效的方法可以从数组中获取“最大值”或“最小值”值。同样,可以在映射器中应用类似的三元组。看看我的回答,里面也有链接。
  • 我同意尼尔的观点。在问这里之前,我使用了 mapReduce,我的工作在 120 秒内完成。使用聚合 fw 和 Neil 的解决方案不到 20 秒。谢谢
猜你喜欢
  • 2017-08-31
  • 2019-02-20
  • 2014-02-24
  • 2022-06-14
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多