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 提供的所有功能还没有那么丰富的经验。

有没有办法计算某些值在购买事件出现之前的出现次数?

试试这个聚合

  1. $match - 按 gameId
  2. 过滤
  3. $sort - 按时间戳排序文档
  4. $group - 累积所有匹配到一个数组
  5. $addFields - $reduce 计算杀戮、过滤并将杀戮映射到文档
  6. $unwind - 获取原始文档结构的平面数组
  7. $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
}
>