0

Players という名前の MongoDB コレクションがあります

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

各プレイヤーのさまざまな統計を毎日更新しますが、新しい値が見つかった場合にのみ統計値を更新します (つまり、new.stCount > existing.stCountC)。私の一般的な考えは、統計配列を一意ごとに 2 つのオブジェクトに制限することですstName。1 つは現在の値用で、もう 1 つは以前の値用です。したがって、たとえば、カウントが 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 } } })

Players3)コレクションを更新する -

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 コレクションの現在の統計値のデータ グリッドを表示します (つまり、プレーヤーごとに 1 行、統計名ごとに 1 列)。統計値の傾向を示すビューも用意し、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 に答える