我正在尝试计算客户第二笔订单的平均订单金额。
我使用以下方法成功完成了第一个订单的平均金额:
db.users.aggregate([
{$match: {
$and: [
{$nor : [ { "emails.0.address" : "X@X.com" }, { "X.0.X" : "X@X.com" },{ "emails.0.address" : "X@X.com" },{ "emails.0.address" : "X@X.fr" } ]},
{orders: {$exists: true}}
]
}},
{$unwind: "$orders"},
{$group: {
_id: "$_id",
firstOrder: {$first: "$orders"}
}},
{$group: {
_id: "$_id",
total: {$sum: "$firstOrder.total"}
}},
{$group: {
_id: '',
average: {$avg: "$total"}
}}
])
但是计算二阶的平均数量似乎有点不同。
我尝试使用$Slice
,但它不适用于aggregate
和$Skip
只跳过列表的第一个订单,而不是每个用户的第一个订单。
你对此有任何想法吗?
非常感谢你的帮助。 理查德
答案 0 :(得分:0)
正如您基本上已经解决的那样,没有一种简单的方法可以获得数组的nth
位置。但是你在正确的轨道上,只需要更多的处理和额外的调整。由于您不希望在没有二阶订单的情况下处理订单:
db.users.aggregate([
// Match to make sure there is a second element, $and is actually implicit
{ "$match": {
"$nor" : [
{ "emails.0.address" : "X@X.com" },
{ "X.0.X" : "X@X.com" },
{ "emails.0.address" : "X@X.com" },
{ "emails.0.address" : "X@X.fr" }
],
"orders.1": { "$exists": true }
}},
// Then unwind to de-normalize
{ "$unwind": "$orders"},
// Keep the first order, and all the rest
{ "$group": {
"_id": "$_id",
"firstOrder": { "$first": "$orders" }
"orders": { "$push": "$orders" }
}},
// Yep, unwind again
{ "$unwind": "$orders"},
// Test to see the element that was already seen
{ "$project": {
"orders": 1,
"matched": { "$eq": [ "$orders", "$firstOrder" ] }
}},
// Filter out the matched element
{ "$match": { "matched": false } },
// Now the $first element is actually the "second"
{ "$group": {
"_id": "$_id",
"secondOrder": { "$first": "$orders" }
}},
// Summing is redundant, just average over all of it
{ "$group": {
"_id": null,
"average": { "$avg": "$secondOrder.total" }
}}
])
因此,通过有效地删除"第一个"来清除一些东西并获得第二个元素的平均值。结束操作中数组的元素。
如果你错过了早期行的含义:
"orders.1": { "$exists": true }
基本上是一个小点符号"确保数组的第二个元素确实存在的技巧。有办法考虑"第一"数组的元素,当实际上没有第二个元素,但这可能是另一个问题,如果你在这里找不到答案。我知道我之前已经给出了处理不同数组长度的方法。