MongoDB数据模型和更新策略

时间:2013-11-14 10:43:22

标签: mongodb

我有一个名为Players的MongoDB集合

_id, name, stats[ { stName, stValue, stCountC } ]

我将每天为每个玩家更新各种统计数据,但只会在找到新值时更新Stat值(即new.stCount > existing.stCountC)。我的一般想法是将stats数组限制为每个唯一stName的2个对象 - 一个用于Current值,一个用于Previous值。因此,举个例子,假设我找到一个数为6的新统计数据,我的查询和更新过程将以 -

开头
db.players.findOne({ name: "JSmith",
                     stats: { $elemMatch: { stName: "Avg", stCountC: 5 } } })

如果上面的查询返回一个文档,那么我更新如下 -

1)获取JSmith的stValue stName = "Avg"stCountP = 4 -

db.players.findOne({ name: "JSmith", stats: { stName: "Avg", stCountP: 4 } },
                   { stats.$.stValue })

2)将此值插入我的StatsHistory集合,该集合包含单个统计类型的每个玩家的所有历史值 -

db.statshistory.update({ Name: "JSmith", StatName: "Avg" },
                       { $addToSet : { oldValues : { stValue: <val>, stCount: 4 } } })

3)更新我的Players集合 -

db.players.update({ Name: JSmith },
                  { $push: { stats: { stName: "Avg", stValue: "98", stCountC: 6 } }
                    $pull: { stats: { stName: "Avg", stCountP: 4 } } })

db.players.update({ name: "JSmith", stats.stName: "Avg", stats.stCountC: 5 },
                  { $rename: { "stats.stCountC": "stats.stCountP" } })

我将从Players集合中呈现当前统计值的数据网格(即每个玩家一行,每个统计名称一列)。我还将提供显示stat值趋势的视图,并假设我将使用MongoDB的Aggregation函数从我的StatsHistory集合中返回这些。

问题:上述数据模型和查找/更新过程是否合乎逻辑?

我显然是MongoDB的新手,所以对任何语法错误表示道歉,或者上述内容似乎完全不适合我的需求。任何反馈都非常感谢!

解决: 感谢idbentley提供以下建议。它帮助我使用async.js设计了以下数据库更新过程。请注意,数据模型稍有变化 - Players集合现在仅保留最新的统计值,每次尝试更新都会更新主记录上的LastScan日期戳,每个统计更新都会提供日期戳LastUpdate。统计计数仍用于检查返回的stat是否更新。此过程还可确保将任何新玩家/统计数据插入到集合中。

async.series([
  function(cb){ db.statshistory.update({ Name: <name>, StatName: <statname> },
                                       { $set : { LastScan: new Date() }},
                                       { upsert: true },
                                       function() { cb(); });
  }
  ,function(cb){ db.statshistory.update({ Name: <name>, StatName: <statname>, OldValues: { $not : { $elemMatch : { StCount: <statcount> }}}},
                                        { $push : { OldValues: { LastUpdate: new Date(), StCount: <statcount>, StValue: <statvalue> }}},
                                        function() { cb(); });
  }
  ,function(cb){ db.players.update({ Name: <name> },
                                   { $set : { LastScan: new Date() }},
                                   { upsert: true },
                                   function() { cb(); });
  }
  ,function(cb){ db.players.update({ Name: <name> },
                                   { $pull : { Stats: { StName: <statname>, StCount: { $ne: <statcount> }}}},
                                   function() { cb(); });
  }
  ,function(cb){ db.players.update({ Name: <name>, Stats: { $not : { $elemMatch : { StName: <statname>, StCount: <statcount> }}}},
                                   { $push : { Stats: { LastUpdate: new Date(), StCount: <statcount>, StValue: <statvalue> }}},
                                   function() { cb(); });
  }]
  ,function() { console.log('update complete'); }
)

1 个答案:

答案 0 :(得分:1)

我认为你可能会使事情变得更加复杂。

我对您的要求的理解:

  1. 每位玩家都有一些随时间变化的统计数据。
  2. 随着时间的推移,我们应该保持球员统计数据的完整历史记录,但通常我们只需要当前和以前的统计数据
  3. 如果我理解正确,那么我会稍微改变一下。

    首先,我会在嵌入的current文档中添加stats标记。

    然后您的工作流程变为:

    db.statshistory.update( { Name: <name>, StatName: <statname> },
        { $addToSet : { oldValues : { <statobj> } } } );
    
    db.player.update( { Name: <name>, stats:
        { $elemMatch: { stName: <statname>} } },
        { $pull: { current: false } } );
    
    db.player.update( {Name: <name>, stats: 
        { $elemMatch: { stName: <statname>, current: true } } },
        { $set: { stats.current: false } } );
    
    db.player.update({Name: <name>},
        { $addToSet: { <statobj>, current: true } });
    

    因为它使用多个更新,所以在多线程环境中无法正常工作。