【问题标题】:MongoDB running total like aggregation of previous records up until occurrance of valueMongoDB 运行总计,就像以前记录的聚合一样,直到出现值
【发布时间】:2018-02-23 21:34:35
【问题描述】:

我目前正在为各种比赛处理一组游戏内事件。在游戏中可以杀死敌人并在商店购买物品。

我现在一直在尝试做的,是计算在每次购买活动之前单场比赛中发生的击杀次数。

{
    "_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 提供的所有功能还没有那么熟练。

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

【问题讨论】:

    标签: mongodb mapreduce aggregation-framework cumulative-sum


    【解决方案1】:

    试试这个聚合

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

    收藏

    > 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
    }
    > 
    

    【讨论】:

    • 非常感谢您的回答!它确实在一定程度上解决了我的问题。但是,我认为我们可以摆脱“kills”数组,对吗?由于实际的击杀数将增加为“计数”,并且事件会按条件放置在“数据”中。
    • @DwayneHart,是的,我昨天做了一些修改,不需要,我们可以删除它
    • 是否还有一种引入并行化的方法,例如在减少步骤中?我正在处理至少 18GB 大小的数据集,并希望尽可能地利用我的多线程六核处理器。
    猜你喜欢
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多