如何聚合集合并查找最小/最大值

时间:2014-04-04 12:38:14

标签: mongodb mongodb-query aggregation-framework

我有一个“订单”集合,如下所示:

{ 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",
         }
     }
    ])

感谢您的时间。

2 个答案:

答案 0 :(得分:3)

您可能还不知道$cond运算符作为三元条件。所以基本上如果作为第一个参数给出的条件是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值。

答案 1 :(得分:0)

也许使用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" }
)

希望有所帮助