Reputation: 754
I have an "orders" collection which is like this:
{ 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 }
and I want to aggregate this collection and find the best buy/sell price for each typeid.
The result should be:
{ typeID: 1, bestBuy: 100, bestSell: 120 }
{ typeID: 2, bestBuy: 500, bestSell: 610 }
Define bestBuy / bestSell
bestBuy = (buyOrder = true && max price)
bestSell = (buyOrder = false && min price)
This is what I have so far but I know that its wrong. Any ideas ?
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",
}
}
])
Thanks for your time.
Upvotes: 2
Views: 6503
Reputation: 151112
You may not yet be aware of the $cond
operator which works as a ternary condition. So basically if a condition given a as a first argument is true
then use the value in the next argument. If the condition evaluates to false
then use the value in the last condition in the operator.
This turns out to be perfect as you already have an indicator of true or false to determine the field
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 } }
])
So the use of $max
and $min
here can negate the null
values in the results where the condition was not met.
Upvotes: 3
Reputation: 499
Maybe with a mapreduce you can achieve this with something like that :
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" }
)
Hope it helped
Upvotes: 0