我正在使用nodejs和mongod(非mongoose)创建一个应用程序.我有一个让我头疼几天的问题,有人请为此提出建议!! 我有这样的mongodb设计
post{
_id:ObjectId(...),
picture: 'some_url',
comments:[
{_id:ObjectId(...),
user_id:Object('123456'),
body:"some content"
},
{_id:ObjectId(...),
user_id:Object('...'),
body:"other content"
}
]
}
user{
_id:ObjectId('123456'),
name: 'some name', --> changable at any times
username: 'some_name', --> changable at any times
picture: 'url_link' --> changable at any times
}
Run Code Online (Sandbox Code Playgroud)
我想查询帖子以及所有用户信息,以便查询如下所示:
[{
_id:ObjectId(...),
picture: 'some_url',
comments:[
{_id:ObjectId(...),
user_id:Object('123456'),
user_data:{
_id:ObjectId('123456'),
name: 'some name',
username: 'some_name',
picture: 'url_link'
}
body:"some content"
},
{_id:ObjectId(...),
user_id:Object('...'),
body:"other content"
}
]
}]
Run Code Online (Sandbox Code Playgroud)
我试图使用循环手动获取用户数据并添加到评论,但它证明是困难的,并且我的编码技能无法实现:(
请任何人有任何建议,我将非常感激.
P/s我正在尝试另一种方法,我将所有用户数据嵌入到评论中,并在用户更新其用户名,名称或图片时.他们也将在所有评论中更新它
正如之前写的,有几个问题,当过嵌入:
截至撰写本文时,BSON文档限制为16MB.如果达到该限制,MongoDB将抛出异常并且您根本无法添加更多注释,并且在最坏的情况下甚至不会更改(用户)名称或图片(如果更改会增加文档的大小).
在某些条件下查询或排序注释数组是不容易的.有些事情需要相当昂贵的汇总,有些则需要相当复杂的陈述.
虽然有人可能会争辩说,一旦查询到位,这不是什么大问题,我不同意.首先,对于开发人员和随后的MongoDBs查询优化器来说,查询越复杂,优化就越困难.通过简化数据模型和查询,我获得了最佳结果,在一个实例中将响应速度提高了100倍.
在缩放时,与简单的数据模型和查询相比,复杂和/或昂贵查询所需的资源甚至可能总结为整个机器.
最后但并非最不重要的是,您可能会遇到维护代码的问题.作为一个简单的经验法则
代码越复杂,维护起来就越困难.更难的代码是维护,维护代码所需的时间越多.维护代码所需的时间越多,代码就越昂贵.
结论:复杂的代码很昂贵.
在这种情况下,"昂贵"既指钱(专业项目),也指时间(爱好项目).
这很简单:简化数据模型.因此,您的查询将变得不那么复杂,并且(希望)更快.
这对我来说是一个疯狂的猜测,但重要的是向你展示一般方法.我将您的用例定义如下:
首先,我们有一个简单的用户模型
{
_id: new ObjectId(),
name: "Joe Average",
username: "HotGrrrl96",
picture: "some_link"
}
Run Code Online (Sandbox Code Playgroud)
这里没有什么新东西,只是为了完整性而添加.
{
_id: new ObjectId()
title: "A post",
content: " Interesting stuff",
picture: "some_link",
created: new ISODate(),
author: {
username: "HotGrrrl96",
picture: "some_link"
}
}
Run Code Online (Sandbox Code Playgroud)
这就是一篇文章.这里有两点需要注意:首先,我们存储我们在显示帖子时立即需要的作者数据,因为这样可以节省我们对一个非常常见(如果不是普遍存在的)用例的查询.为什么我们不按顺序保存评论和评论者的数据?由于16 MB大小限制,我们正在尝试阻止在单个文档中存储引用.相反,我们将引用存储在注释文档中:
{
_id: new ObjectId(),
post: someObjectId,
created: new ISODate(),
commenter: {
username: "FooBar",
picture: "some_link"
},
comment: "Awesome!"
}
Run Code Online (Sandbox Code Playgroud)
与帖子相同,我们拥有显示帖子的所有必要数据.
我们现在取得的成就是我们规避了BSON大小限制,我们不需要引用用户数据就可以显示帖子和评论,这可以为我们节省大量的查询.但是让我们回到用例和更多查询
那现在完全是直截了当的.
对于所有评论
db.comments.find({post:objectIdOfPost})
Run Code Online (Sandbox Code Playgroud)
对于最新的3条评论
db.comments.find({post:objectIdOfPost}).sort({created:-1}).limit(3)
Run Code Online (Sandbox Code Playgroud)
因此,为了显示帖子及其所有(或部分)评论,包括用户名和图片,我们有两个查询.比以前更需要,但我们规避了大小限制,基本上你可以为每个帖子提供无限数量的评论.但是,让我们做一些真实的事情
这是一个两步过程.但是,通过适当的索引(将在稍后回归),这仍然应该是快速的(因此节省资源):
var posts = db.posts.find().sort({created:-1}).limit(5)
posts.forEach(
function(post) {
doSomethingWith(post);
var comments = db.comments.find({"post":post._id}).sort("created":-1).limit(3);
doSomethingElseWith(comments);
}
)
Run Code Online (Sandbox Code Playgroud)
var posts = db.posts.find({"author.username": "HotGrrrl96"},{_id:1}).sort({"created":-1});
var postIds = [];
posts.forEach(
function(post){
postIds.push(post._id);
}
)
var comments = db.comments.find({post: {$in: postIds}}).sort({post:1, created:-1});
Run Code Online (Sandbox Code Playgroud)
请注意,我们这里只有两个查询.虽然你需要"手动"建立帖子和他们各自的评论之间的联系,这应该是非常简单的.
这可能是一个罕见的用例.然而,所述数据模型并不是很复杂
首先,我们更改用户文档
db.users.update(
{ username: "HotGrrrl96"},
{
$set: { username: "Joe Cool"},
$push: {oldUsernames: "HotGrrrl96" }
},
{
writeConcern: {w: "majority"}
}
);
Run Code Online (Sandbox Code Playgroud)
我们将旧用户名推送到相应的数组.这是一种安全措施,以防以下操作出现问题.此外,我们将写入问题设置为相当高的级别,以确保数据持久.
db.posts.update(
{ "author.username": "HotGrrrl96"},
{ $set:{ "author.username": "Joe Cool"} },
{
multi:true,
writeConcern: {w:"majority"}
}
)
Run Code Online (Sandbox Code Playgroud)
这里没什么特别的.注释的更新语句看起来几乎相同.虽然这些查询需要一些时间,但很少执行.
根据经验,可以说MongoDB每个查询只能使用一个索引.虽然这不完全正确,因为有索引交叉点,很容易处理.另一件事是复合索引中的各个字段可以独立使用.因此,索引优化的一种简单方法是查找具有使用索引的操作中使用的大多数字段的查询,并创建它们的复合索引.请注意,查询中出现的顺序很重要.那么,让我们继续吧.
db.posts.createIndex({"author.username":1,"created":-1})
Run Code Online (Sandbox Code Playgroud)
db.comments.createIndex({"post":1, "created":-1})
Run Code Online (Sandbox Code Playgroud)
每个帖子完全嵌入的文档无疑是加载它的最快方式和它的评论.但是,它不能很好地扩展,并且由于处理它所需的复杂查询的性质,可以利用甚至消除这种性能优势.
通过上面的解决方案,您可以将一些速度(如果!)与基本无限的可伸缩性和更直接的数据处理方式进行交易.
心连心.
| 归档时间: |
|
| 查看次数: |
2524 次 |
| 最近记录: |