我有一个名为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'); }
)
答案 0 :(得分:1)
我认为你可能会使事情变得更加复杂。
我对您的要求的理解:
如果我理解正确,那么我会稍微改变一下。
首先,我会在嵌入的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 } });
因为它使用多个更新,所以在多线程环境中无法正常工作。