我有一个应用程序,它监听websocket并存储用户名/用户ID(用户名是1-20个字节,用户ID是17个字节)。这不是什么大问题,因为它只有一个文档。但是,在他们参与的每一轮中,它都会推送圆形ID(24个字节)和一个“得分”十进制值(例如:1190.0015239999999)。
问题是,对于有多少回合没有限制,而且我无法承担每月为蒙戈拉支付这么多钱的费用。处理这些数据的最佳方法是什么?
我的想法: - 如果有办法替换mongodb中的_id:字段,我将用17字节长的userID替换它。不知道我是否可以这样做。
使用时间戳存储用户数据,并删除分数值小于200的OLD数据。
切断超过10个字符的用户名。
完全删除Round ID(或用roundId替换_id字段)。(由于每个文档中有多个roundID,因此无效)
将小数值四舍五入到两个位置。
30天后删除回合ID
tl; dr
需要有效地存储数据< mongo lab 500 mb
文件包括用户名(1-20个字符),用户ID(17个字符),圆形(对象数组)= [{round Id(24个字符),得分(1190.0015239999999)}]。
< / LI>提前致谢!
修改
文档架构:
userID: {type: String},
userName: {type: String},
rounds: [{roundID: String, score: String}]
答案 0 :(得分:1)
建模1:n作为嵌入式文档的关系不是最好的,除非极少数情况。这是因为在撰写本文时,BSON文档的大小限制为16MB。
更好(阅读更具可扩展性和效率的方法)是使用document references。
首先,您需要您的播放器数据。这是一个例子:
{
_id: "SomeUserId",
name: "SomeName"
}
不需要额外的userId
字段,因为每个文档都需要具有唯一值的_id
字段。与流行的看法相反,这个字段值不一定是ObjectId。因此,如果我没有弄错的话,我们已经将玩家数据所需的大小减少了1/3。
接下来,每轮结果:
{
_id: {
round: "SomeString",
player: "SomeUserId"
},
score: 5,
createdAt: ISODate("2015-04-13T01:03:04.0002Z")
}
这里要注意一些事情。首要的是: NOT 使用字符串来记录值。甚至等级也应该存储为相应的数值。否则你无法获得平均值等。我稍后会再说明一点。我们在这里使用_id
的复合字段,这是完全有效的。此外,它将为我们提供一个免费索引,优化一些最有可能的查询,例如“玩家X如何在Y轮中得分?”
db.results.find({"_id.player":"X","_id.round":"Y"})
或“Y轮的结果在哪里?”
db.results.find({"_id.round":"Y"})
或“我们在各轮比赛中得分是什么?”
db.results.find({"_id.player":"X"})
但是,不使用字符串来保存分数,即使是一些漂亮的统计数据也变得相当便宜,例如“Y轮的平均得分是多少?”
db.results.aggregate(
{ $match: { "_id.round":"Y" } },
{ $group: { "round":"$_id.round", "averageScore": {$avg:"$score"} }
)
或“各轮次中每位球员的平均得分是多少?”
db.results.aggregate(
{ $group: { "player: "$_id.player", "averageAll": {$avg:"$score"} }
)
虽然您可以在应用程序中执行这些计算,但MongoDB可以更有效地执行这些计算,因为在处理数据之前不必将数据发送到您的应用程序。
接下来,对于数据过期。我们有一个createdAt
字段,类型为ISODate。现在,我们让MongoDB通过创建TTL index
db.results.ensureIndex(
{ "createdAt":1 },
{ expireAfterSeconds: 60*60*24*30}
)
总而言之,这应该是存储和过期数据的最有效方式,同时提高可扩展性。
答案 1 :(得分:0)
因此,目前您在数组中为每条记录存储三个数据点。
_id:false将阻止mongoose自动为文档创建id。如果您不需要roundID,那么您可以使用以下仅在数组中存储一个数据点的内容:
round[{_id:false, score:String}]
否则如果roundID实际上有意义,请使用以下内容在数组中存储两个数据点:
round[{_id:false, roundID: string, score:String}]
最后,如果您只需要一个ID用于参考,请使用以下内容,它将在数组中存储两个数据点 - 随机ID和分数:
round[{score:String}]