MongoDB 运行 以前记录的总计,直到出现值
MongoDB running total like aggregation of previous records up until occurrance of value
我目前正在处理各种比赛的一组游戏内事件。在游戏中可以杀死敌人并在商店购买物品。
我现在一直在尝试做的是计算在每次购买事件之前单场比赛中发生的击杀数。
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"victimId" : 9,
"type" : "ENEMY_KILLED",
"timestamp" : 745245 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"victimId" : 7,
"type" : "ENEMY_KILLED",
"timestamp" : 746223 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245 },
这是我想要的结果:
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664,
"kills": 0 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245 ,
"kills": 2 }
虽然我倾向于认为这是不可能的,但我对 mongo 提供的所有功能还没有那么丰富的经验。
有没有办法计算某些值在购买事件出现之前的出现次数?
试试这个聚合
$match
- 按 gameId 过滤
$sort
- 按时间戳排序文档
$group
- 累积所有匹配到一个数组
$addFields
- $reduce
计算杀戮、过滤并将杀戮映射到文档
$unwind
- 获取原始文档结构的平面数组
$replaceRoot
- 将数据移动到原始结构中的顶层
流水线
db.games.aggregate([
{$match : {gameId : 1}},
{$sort : {timestamp : 1}},
{$group : {_id : "$gameId", data : {$push : "$$ROOT"}}},
{$addFields : {data : {
$reduce : {
input : "$data",
initialValue : {kills : [], data : [], count : 0},
in : {
count : {$sum : ["$$value.count", {$cond : [{$eq : ["$$this.type", "ENEMY_KILLED"]}, 1, 0]}]},
data : { $concatArrays : [
"$$value.data",
{$cond : [
{$ne : ["$$this.type", "ENEMY_KILLED"]},
[
{
_id : "$$this._id",
gameId : "$$this.gameId",
participantId : "$$this.participantId",
type : "$$this.type",
timestamp : "$$this.timestamp",
kills : {$sum : ["$$value.count", {$cond : [{$eq : ["$$this.type", "ENEMY_KILLED"]}, 1, 0]}]}
}
],
[]
]}
]}
}
}}
}},
{$unwind : "$data.data"},
{$replaceRoot : {newRoot : "$data.data"}}
]).pretty()
collection
> db.games.find()
{ "_id" : 1, "gameId" : 1, "participantId" : 3, "type" : "ITEM_PURCHASED", "timestamp" : 656664 }
{ "_id" : 2, "gameId" : 1, "participantId" : 3, "victimId" : 9, "type" : "ENEMY_KILLED", "timestamp" : 745245 }
{ "_id" : 3, "gameId" : 1, "participantId" : 3, "victimId" : 7, "type" : "ENEMY_KILLED", "timestamp" : 746223 }
{ "_id" : 4, "gameId" : 1, "participantId" : 3, "type" : "ITEM_PURCHASED", "timestamp" : 840245 }
结果
{
"_id" : 1,
"gameId" : 1,
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664,
"kills" : 0
}
{
"_id" : 4,
"gameId" : 1,
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245,
"kills" : 2
}
>
我目前正在处理各种比赛的一组游戏内事件。在游戏中可以杀死敌人并在商店购买物品。
我现在一直在尝试做的是计算在每次购买事件之前单场比赛中发生的击杀数。
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"victimId" : 9,
"type" : "ENEMY_KILLED",
"timestamp" : 745245 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"victimId" : 7,
"type" : "ENEMY_KILLED",
"timestamp" : 746223 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245 },
这是我想要的结果:
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664,
"kills": 0 },
{
"_id" : ObjectId("5988f89ae5873exxxxxxx"),
"gameId" : NumberLong(2910126xxx)
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245 ,
"kills": 2 }
虽然我倾向于认为这是不可能的,但我对 mongo 提供的所有功能还没有那么丰富的经验。
有没有办法计算某些值在购买事件出现之前的出现次数?
试试这个聚合
$match
- 按 gameId 过滤
$sort
- 按时间戳排序文档$group
- 累积所有匹配到一个数组$addFields
-$reduce
计算杀戮、过滤并将杀戮映射到文档$unwind
- 获取原始文档结构的平面数组$replaceRoot
- 将数据移动到原始结构中的顶层
流水线
db.games.aggregate([
{$match : {gameId : 1}},
{$sort : {timestamp : 1}},
{$group : {_id : "$gameId", data : {$push : "$$ROOT"}}},
{$addFields : {data : {
$reduce : {
input : "$data",
initialValue : {kills : [], data : [], count : 0},
in : {
count : {$sum : ["$$value.count", {$cond : [{$eq : ["$$this.type", "ENEMY_KILLED"]}, 1, 0]}]},
data : { $concatArrays : [
"$$value.data",
{$cond : [
{$ne : ["$$this.type", "ENEMY_KILLED"]},
[
{
_id : "$$this._id",
gameId : "$$this.gameId",
participantId : "$$this.participantId",
type : "$$this.type",
timestamp : "$$this.timestamp",
kills : {$sum : ["$$value.count", {$cond : [{$eq : ["$$this.type", "ENEMY_KILLED"]}, 1, 0]}]}
}
],
[]
]}
]}
}
}}
}},
{$unwind : "$data.data"},
{$replaceRoot : {newRoot : "$data.data"}}
]).pretty()
collection
> db.games.find()
{ "_id" : 1, "gameId" : 1, "participantId" : 3, "type" : "ITEM_PURCHASED", "timestamp" : 656664 }
{ "_id" : 2, "gameId" : 1, "participantId" : 3, "victimId" : 9, "type" : "ENEMY_KILLED", "timestamp" : 745245 }
{ "_id" : 3, "gameId" : 1, "participantId" : 3, "victimId" : 7, "type" : "ENEMY_KILLED", "timestamp" : 746223 }
{ "_id" : 4, "gameId" : 1, "participantId" : 3, "type" : "ITEM_PURCHASED", "timestamp" : 840245 }
结果
{
"_id" : 1,
"gameId" : 1,
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 656664,
"kills" : 0
}
{
"_id" : 4,
"gameId" : 1,
"participantId" : 3,
"type" : "ITEM_PURCHASED",
"timestamp" : 840245,
"kills" : 2
}
>