0

我有一个名为 Players 的 MongoDB 集合

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

我将每天更新每个玩家的各种统计数据,但只会在找到新值时更新统计值(即new.stCount > existing.stCountC)。我的一般想法是将 stats 数组限制为每个唯一的 2 个对象stName——一个用于当前值,一个用于上一个值。因此,举例来说,假设我找到一个计数为 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 集合的当前统计值的数据网格(即每个玩家一行,每个统计名称一列)。我还将有显示统计值趋势的视图,并假设我将使用 MongoDB 的聚合函数从我的 StatsHistory 集合中返回这些。

问题:上述数据模型和查找/更新过程看起来合乎逻辑吗?

我显然是 MongoDB 的新手,因此对于任何语法错误或以上内容似乎完全不适合我的需求,我深表歉意。非常感谢任何反馈!

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

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'); }
)
4

1 回答 1

1

我认为你可能会让事情变得比必要的更复杂。

我对您的要求的理解:

  1. 每个玩家都有一些随时间变化的统计数据。
  2. 我们应该保持球员统计数据的完整历史,但大多数情况下我们只需要当前和以前的统计数据

如果我理解正确,那么我会稍微改变一下。

首先,我会在嵌入文档中添加一个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 } });

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

于 2013-11-20T21:48:15.243 回答