我对MongoDB的聚合框架很新,所以我不知道如何做到这一点。
我的数据模型结构如下:
{
name: String,
store: {
item1: Number,
item2: Number,
item3: Number,
item4: Number,
},
createdAt: Date
}
我想要退回每件商品的平均价格' i'。我正在尝试使用此查询:
db.commerces.aggregate([
{
$group: {
_id: "",
item1Avg: { $avg: "$store.item1"},
item2Avg: { $avg: "$store.item2"},
item3Avg: { $avg: "$store.item3"},
item4Avg: { $avg: "$store.item4"}
}
}
]);
问题在于,当某个商品没有设定价格时,它会以" -1"的形式存储在数据库中。
我不希望这些值污染平均结果。有没有办法限制agreggation只考虑价格> 0
$match
之前的 $group
运算符不是解决方案,因为我想返回所有平均价格。
谢谢!
编辑:这里有一个输入&的例子。期望的输出:
[{
name: 'name',
store: {
item1: 10,
item2: -1,
item3: 12,
item4: 3,
}
},
{
name: 'name2',
store: {
item1: 10,
item2: -1,
item3: -1,
item4: 2,
}
},...]
所需的输出:
{
item1Avg: 10,
item2Avg: 0,
item3Avg: 12,
item4Avg: 2.5
}
答案 0 :(得分:1)
您需要$unwind store
,然后$match值才能满足您的条件,然后$group通过测试。遗憾的是,无法$unwind一个对象,所以你需要$project首先排列一个对象:
db.commerces.aggregate([
{$project: {store:[
{item:{$literal:"item1"}, val:"$store.item1"},
{item:{$literal:"item2"}, val:"$store.item2"},
{item:{$literal:"item3"}, val:"$store.item3"},
{item:{$literal:"item4"}, val:"$store.item4"}
]}},
{$unwind:"$store"},
{$match: {"store.val":{$gt:0}}},
{$group: {_id:"$store.item", avg:{$avg:"$store.val"}}}
])
修改强>
正如@ blakes-seven指出的那样,它可能不适用于版本< 3.2。使用$map的替代方法可能有效:
db.commerces.aggregate([
{$project: {
store: {
$map:{
input:[
{item:{$literal:"item1"}, val:"$store.item1"},
{item:{$literal:"item2"}, val:"$store.item2"},
{item:{$literal:"item3"}, val:"$store.item3"},
{item:{$literal:"item4"}, val:"$store.item4"}
],
as: "i",
in: "$$i"
}
}
}},
{$unwind:"$store"},
{$match: {"store.val":{$gt:0}}},
{$group: {_id:"$store.item", avg:{$avg:"$store.val"}}}
])