我决定尝试将MongoDB用于我正在开发的游戏的后端服务器,但我没有数据库设计或设置的背景知识。也就是说,数据库似乎相当基础,大多数交易都是简单更新或查找查询。
我的架构的简化版本是这样的(实际上我的_id是数字并且保证唯一,对于索引来说是完美的):
users_collection
{
_id: 11111,
nameFirst: "Bilbo",
nameLast: "Baggins"
friends: [222222,3333333,444444],
userScores:[
{ level: "OtherGameType", scores:
[{score: 150},{score: 250},{score: 350}] },
{ level: "Level1", scores: [{score: 200}] },
{ level: "Level2", scores: [{score: 200}] }
]
}
我的问题是我无法从所有该用户的朋友那里找到给定级别的最高X分数列表的好方法。最终,我希望输出是这样的:
[ {nameFirst:"Martin", nameLast:"Freeman", score:2012},
{nameFirst:"Ian", nameLast:"Holm", score:2001},
{nameFirst:"Norman", nameLast:"Bird", score:1978} ]
最好的方法是什么?
一个问题是某人可能拥有非常多的朋友(500?1000?),每个朋友都有一个20或50分的特定级别的列表(而其他级别只会跟踪1到3个分数)。我意识到数据库通常以数百万的方式工作,但我很紧张,如果这是客户的共同呼叫,这可能会影响性能。
顺便说一下,我正在连接到Node.js中的服务器(在同一台服务器上),连接到它的目标设备将是通过REST请求的浏览器和移动设备。也就是说,如果需要或建议,我非常愿意重新构建模式或将某些计算推送到不同的层。所有建设性的批评都欢迎!
tl; dr:在重新设计数据库作为选项的情况下,如何从给定用户的朋友中检索最高X分数列表?
谢谢你的时间!
答案 0 :(得分:1)
这个模型似乎并没有考虑到。您将所有分数附加到用户和附加的朋友列表。如果这不会太大,这应该没问题,并且它为您提供了大量单个读/写操作所需的功能。
但是看一下重要的部分,让我们得到你想要的信息。所以你在某个时候需要朋友的列表,你已经在文档中有一个:
{
_id: 11111,
friends: [222222,3333333,444444],
userScores:[
{ level: "OtherGameType", scores:
[{score: 150},{score: 250},{score: 350}] },
{ level: "Level1", scores: [{score: 200}] },
{ level: "Level2", scores: [{score: 200}] }
]
}
因此,给定某个用户,并且已将文档检索到名为user
的变量中,您可以使用aggregate使用朋友列表来回询该集合:
db.users.aggregate([
// Match all the friends and try to filter out results that have no
// score for that level. Keeping the set size down
{ "$match": {
"_id": { "$in": user.friends }
"userScores.level": "Level1",
}},
// Unwind the userScores
{ "$unwind": "$userScores" },
// Really filter out the level that does not match
{ "$match": { "userScores.level": "Level1" } },
// Unwind the scores per level for the remaining results
{ "$unwind": "$scores"},
// Group by user ("friend") to find the top scores
{ "$group": {
"_id": "$_id",
"topScore": { "$max": "$userScores.scores.score"}
}},
// Sort the results by topScore descending
{ "$sort": { "topScore": -1 } },
// Optionally limit to "n" results
{ "$limit": 10 }
])
你基本上拥有它。所有用户朋友在关卡中排名前10位(如果有那么多)。
至于所有您的其他问题,这些问题可能最好在他们自己的背景下作为他们自己的问题呈现。我知道有一种诱惑可以一次性询问所有问题,特别是当你找到某人的答案时,你将通过分离它们来获得更有意义的答案。
关于你的架构的最后一点说明。虽然它应该适用于大多数事情,但我只想指出您已经通过在userScores
数组中包含内部分数列表来引入嵌套数组。您需要注意的是使用positional operator更新这些项目的限制。
这是可以解决的问题,但你应该知道这些问题。
其他有价值的阅读,更多是关于aggregation operators和更多的管道流程。如果您经常需要统计类型的结果,那么您可能会使用它。