需求
当在游戏金币变动日志中,金币有正有负,需要按玩家分别统计正值和负值的和时。可以使用$cond
计算表达式
定义
$cond
计算 boolean 表达式以 return 两个指定的 return 表达式之一。mongodb语法:
{ $cond: [ <boolean-expression>, <true-case>, <false-case> ] }
mongodb-driver实现
查询数据
如有玩家金币变动日志数据
{ "_id" : 1, "userId" : "12345", "change": 300 }
{ "_id" : 2, "userId" : "12345", "change": -200 }
{ "_id" : 3, "userId" : "12345", "change": 150 }
{ "_id" : 3, "userId" : "12311", "change": 250 }
mongodb实现
db.getCollection('CoinLog').aggregate({
$group: {
_id: "$userId",
win: {
$sum: {
$cond: [{
$gt: ["$change", 0]
},"$change",0]
}
}
},
lose: {
$sum: {
$cond: [{
$lt: ["$change", 0]
},"$change",0]
}
}
}
})
mongodb-driver实现
这里用的mongodb-driver版本为3.8.2
BsonArray filter = new BsonArray();
filter.add(new BsonString("$change"));
filter.add(new BsonInt64(0));
BsonArray winCond = new BsonArray();
winCond.add(new BsonDocument("$gt", filter));
winCond.add(new BsonString("$change"));
winCond.add(new BsonInt64(0));
BsonArray loseCond = new BsonArray();
loseCond.add(new BsonDocument("$lt", filter));
loseCond.add(new BsonString("$change"));
loseCond.add(new BsonInt64(0));
db.getCollection('CoinLog')
.aggregate(Arrays.asList(
Aggregates.group($userId,
sum("win",new BsonDocument("$cond",winCond)),
sum("lose",new BsonDocument("$cond",loseCond)))
)).forEach(new Block<Document>() {
@Override
public void apply(Document doc) {
String userId = doc.getString("_id");
// 这里要注意一下的是,如果累加值过大,
// 需要先判断类是是int还是long,不然直接getInteger会出错
int win = doc.getInteger("win");
int lose = doc.getInteger("lose");
// TODO
});