Node.js MongoDB查询注释以及用户信息
我正在用nodejs和mongood(不是mongoose)创建一个应用程序。我有一个问题,让我头痛了几天,任何人都请建议一种方法!!。 我有这样的mongodb设计Node.js MongoDB查询注释以及用户信息,node.js,mongodb,Node.js,Mongodb,我正在用nodejs和mongood(不是mongoose)创建一个应用程序。我有一个问题,让我头痛了几天,任何人都请建议一种方法!!。 我有这样的mongodb设计 post{ _id:ObjectId(...), picture: 'some_url', comments:[ {_id:ObjectId(...), user_id:Object('123456'), body:"some content" }, {_id:ObjectI
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
}
我想查询帖子以及所有用户信息,因此查询如下:
[{
_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"
}
]
}]
我尝试使用loop手动获取用户数据并添加到评论中,但事实证明这很困难,而且我的编码技能无法实现:(
如果你有任何建议,我将不胜感激
p/s我正在尝试另一种方法,我会将所有用户数据嵌入到注释中,每当用户更新其用户名、名称或图片时。他们也会在所有注释中更新它。您遵循的是规范化数据模型方法。如果您遵循此模型,则意味着您必须编写另一个查询以获取用户info或者,如果您使用嵌入式文档存储,则每当更新用户文档时,所有用户文档都必须更改。 阅读此链接了解更多信息。问题 如前所述,过度嵌入时存在几个问题: 问题1:BSON大小限制 在撰写本文时,。如果达到该限制,MongoDB将抛出异常,您将无法添加更多注释,在最坏的情况下,如果更改会增加文档的大小,甚至不会更改(用户名)或图片 问题2:查询限制和性能 在某些条件下,查询或排序comments数组是不容易的。有些事情需要相当昂贵的聚合,而有些事情则需要相当复杂的语句 虽然有人可能会说,一旦查询到位,这并不是什么大问题,但我不同意。首先,对于开发人员和随后的MongoDB查询优化器来说,查询越复杂,优化就越困难。我已经通过简化数据模型和查询获得了最好的结果,将响应速度提高了一倍f 100在一个实例中 在扩展时,与更简单的数据模型和相应的查询相比,复杂和/或昂贵的查询所需的资源甚至可能总计为整个机器 问题3:可维护性 最后但并非最不重要的一点是,维护代码时可能会遇到问题 代码越复杂,维护就越困难。代码越难维护,维护代码所需的时间就越多。维护代码所需的时间越多,维护代码的成本就越高 结论:复杂的代码是昂贵的 在这种情况下,“昂贵”指的是金钱(用于专业项目)和时间(用于业余项目) (我的!)解决方案 这很简单:简化数据模型。因此,您的查询将变得不那么复杂,并且(希望)更快 步骤1:确定您的用例 这对我来说是一个猜测,但这里重要的是向您展示一般方法。我将按如下方式定义您的用例:
{
_id: new ObjectId(),
name: "Joe Average",
username: "HotGrrrl96",
picture: "some_link"
}
这里没有什么新内容,只是为了完整性而添加
帖子
这就是关于一篇文章的内容。这里有两件事需要注意:首先,我们在显示一篇文章时存储了我们立即需要的作者数据,因为这为我们保存了一个非常常见(如果不是普遍存在的话)用例的查询。为什么我们不将注释和注释数据按顺序保存?因为ces在单个文档中。相反,我们将引用存储在注释文档中:
评论
与post一样,我们拥有显示post所需的所有数据
疑问
我们现在所取得的成就是,我们绕过了BSON的大小限制,我们不需要为了能够显示帖子和评论而引用用户数据,这将为我们节省大量的查询。但让我们回到用例和一些更多的查询
添加评论
现在这完全是直截了当的
获取给定帖子的全部或部分评论
所有评论
db.comments.find({post:objectIdOfPost})
最新的3条评论
db.comments.find({post:objectIdOfPost}).sort({created:-1}).limit(3)
因此,对于显示一篇文章及其所有(或部分)评论,包括用户名和图片,我们有两个查询。比您以前需要的更多,但我们绕过了大小限制,基本上您可以为每篇文章提供无限数量的评论。但让我们来看看真实的情况
获取最新的5篇帖子和最新的3条评论
这是一个分为两步的过程。但是,通过适当的索引(稍后再讨论),这仍然应该是快速的(从而节省资源):
获取给定用户的所有帖子,从最新到最旧进行排序,并获取其评论
请注意,这里只有两个查询。虽然您需要“手动”在帖子和它们各自的评论之间建立连接,但这应该非常简单
更改用户名
这可能是一个很少执行的用例。然而,对于所说的数据模型来说,它并不是很复杂
首先,我们更改用户文档
db.users.update(
{ username: "HotGrrrl96"},
{
$set: { username: "Joe Cool"},
$push: {oldUsernames: "HotGrrrl96" }
},
{
writeConcern: {w: "majority"}
}
);
我们将旧用户名推送到相应的数组中。这是一种安全措施,以防以下操作出错。此外,我们将写关注点设置为一个相当高的级别,以确保数据的持久性
db.posts.update(
{ "author.username": "HotGrrrl96"},
{ $set:{ "author.username": "Joe Cool"} },
{
multi:true,
writeConcern: {w:"majority"}
}
)
这里没什么特别的。注释的update语句看起来几乎一样。虽然这些查询需要一些时间,但很少执行
指数
根据经验,可以说MongoDB在每个查询中只能使用一个索引
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);
}
)
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});
db.users.update(
{ username: "HotGrrrl96"},
{
$set: { username: "Joe Cool"},
$push: {oldUsernames: "HotGrrrl96" }
},
{
writeConcern: {w: "majority"}
}
);
db.posts.update(
{ "author.username": "HotGrrrl96"},
{ $set:{ "author.username": "Joe Cool"} },
{
multi:true,
writeConcern: {w:"majority"}
}
)
db.posts.createIndex({"author.username":1,"created":-1})
db.comments.createIndex({"post":1, "created":-1})