我对Mongo相对较新,并试图弄清楚如何完成此查询。我在node.js中使用mongoose。我想从嵌入的对象数组中获取sell.amount和buy.amount的总和。交易数组很大,我想将它限制为第一个(从0)n个对象。我希望能够得到像这样的东西:
{buy.totalAmount, buy.tradesCount},{sell.totalAmount, sell.tradesCount},
作为$ limit
选择的元素数量的总和我认为我必须接近,但到目前为止,我无法弄清楚如何使这项工作。
我的查询:
tradePair.aggregate(
{$match: {pair:"STOCK"}},
{$unwind:"$trades"},
{$limit: 20},
{$group : { _id : '$trades.buy',
count : {$sum : 1},
totalAmount: { $sum: '$trades.buy.amount' }
}},
function(err,result){
return result
}
)
我的数据库文档,只显示了2个交易数组元素......很多......
{
"_id" : ObjectId("58fa86c81cdd7b2375cdd4cc"),
"pair" : "STOCK",
"trades" : [
{
"sell" : {
"trades" : 1,
"total" : 0.13309789,
"amount" : 24.80139,
"rate" : 0.00536655
},
"buy" : {
"trades" : 0,
"total" : 0,
"amount" : 0,
"rate" : 0
},
"_id" : ObjectId("58fa87290567372b4035d16f"),
"endTradeId" : 41306,
"startTradeId" : 41306,
"dateEnd" : ISODate("2017-04-21T21:37:39.000Z"),
"dateStart" : ISODate("2017-04-21T21:37:39.000Z")
},
{
"sell" : {
"trades" : 2,
"total" : 1.23879614,
"amount" : 230.83659924,
"rate" : 0.00536655
},
"buy" : {
"trades" : 0,
"total" : 0,
"amount" : 0,
"rate" : 0
},
"_id" : ObjectId("58fa87290567372b4035d16e"),
"endTradeId" : 41305,
"startTradeId" : 41304,
"dateEnd" : ISODate("2017-04-21T21:35:28.000Z"),
"dateStart" : ISODate("2017-04-21T21:35:27.000Z")
},
...,
...,
],
"lastTradeId" : 41306,
"dateStart" : ISODate("2017-04-21T21:37:39.000Z"),
"dateEnd" : ISODate("2017-04-21T21:37:39.000Z"),
"__v" : 0
}
答案 0 :(得分:1)
您可以在Mongo 3.4中使用以下聚合管道。
以下代码将使用$match
阶段来保存匹配的文档。
$project
使用$slice
数组上的trades
返回20个元素,后跟$reduce
,后者获取数组值并将每个文档的值相加。
db.tradePair.aggregate([{
$match: {
pair: "STOCK"
}
},
{
$project: {
trades: {
$reduce: {
"input": {
$slice: ["$trades", 20]
},
initialValue: {
buyTotalAmount: 0,
buyTradesCount: 0,
sellTotalAmount: 0,
sellTradesCount: 0
},
in: {
buyTotalAmount: {
$add: ["$$value.buyTotalAmount", "$$this.buy.amount"]
},
buyTradesCount: {
$add: ["$$value.buyTradesCount", "$$this.buy.trades"]
},
sellTotalAmount: {
$add: ["$$value.sellTotalAmount", "$$this.sell.amount"]
},
sellTradesCount: {
$add: ["$$value.sellTradesCount", "$$this.sell.trades"]
}
}
}
},
_id: 0
}
}
])
更新
在sell.trades
字段的相同管道中添加avg,min和max。
以下查询会将initialValue
设置为$trades.sell.trades
的第一个元素,然后在$lt
上进行sell.trades
比较,如果为true,则设置为$$this
$$value
,如果为false,则保留前一个值,$reduce
所有值都找到最小元素,$gt
找到具有相似逻辑的max元素。此外,添加了count
字段以跟踪交易条目的数量。最外面的$let
读取内部$reduce
的结果,同时将sumsellTradesCount
除以count
来计算平均值。
db.tradePair.aggregate([{
$match: {
pair: "STOCK"
}
},
{
$project: {
trades: {
$let: {
vars: {
obj: {
$reduce: {
"input": {
$slice: ["$trades", 20]
},
initialValue: {
minsellTradesCount: {
$let: {
vars: {
obj: {
$arrayElemAt: ["$trades", 0]
}
},
in: "$$obj.sell.trades"
}
},
maxsellTradesCount: {
$let: {
vars: {
obj: {
$arrayElemAt: ["$trades", 0]
}
},
in: "$$obj.sell.trades"
}
},
sumsellTradesCount: 0,
count: 0
},
in: {
sumsellTradesCount: {
$add: ["$$value.sumsellTradesCount", "$$this.sell.trades"]
},
minsellTradesCount: {
$cond: [{
$lt: ["$$this.sell.trades", "$$value.minsellTradesCount"]
}, "$$this.sell.trades", "$$value.minsellTradesCount"]
},
maxsellTradesCount: {
$cond: [{
$gt: ["$$this.sell.trades", "$$value.minsellTradesCount"]
}, "$$this.sell.trades", "$$value.minsellTradesCount"]
},
count: {
$add: ["$$value.count", 1]
}
}
}
}
},
in: {
minsellTradesCount: "$$obj.minsellTradesCount",
maxsellTradesCount: "$$obj.maxsellTradesCount",
sumsellTradesCount: "$$obj.sumsellTradesCount",
avgsellTradesCount: {
$divide: ["$$obj.sumsellTradesCount", "$$obj.count"]
}
}
}
},
_id: 0
}
}
])
更新2:
在sell.amount
字段的相同管道中添加avg,min和max。
db.tradePair.aggregate([{
$match: {
pair: "STOCK"
}
},
{
$project: {
trades: {
$let: {
vars: {
obj: {
$reduce: {
"input": {
$slice: ["$trades", 20]
},
initialValue: {
minsellTotalAmount: {
$let: {
vars: {
obj: {
$arrayElemAt: ["$trades", 0]
}
},
in: "$$obj.sell.amount"
}
},
maxsellTotalAmount: {
$let: {
vars: {
obj: {
$arrayElemAt: ["$trades", 0]
}
},
in: "$$obj.sell.amount"
}
},
sumsellTotalAmount: 0,
count: 0
},
in: {
minsellTotalAmount: {
$cond: [{
$lt: ["$$this.sell.amount", "$$value.minsellTotalAmount"]
}, "$$this.sell.amount", "$$value.minsellTotalAmount"]
},
maxsellTotalAmount: {
$cond: [{
$gt: ["$$this.sell.amount", "$$value.maxsellTotalAmount"]
}, "$$this.sell.amount", "$$value.maxsellTotalAmount"]
},
sumsellTotalAmount: {
$add: ["$$value.sumsellTotalAmount", "$$this.sell.amount"]
},
count: {
$add: ["$$value.count", 1]
}
}
}
}
},
in: {
minsellTotalAmount: "$$obj.minsellTotalAmount",
maxsellTotalAmount: "$$obj.maxsellTotalAmount",
sumsellTotalAmount: "$$obj.sumsellTotalAmount",
avgsellTotalAmount: {
$divide: ["$$obj.sumsellTotalAmount", "$$obj.count"]
}
}
}
},
_id: 0
}
}
])