Nodejs中Mongodb数据库设计使用嵌套还是引用?

Nodejs中Mongodb数据库设计使用嵌套还是引用?

举个例子,一个blog,支持评论。 是使用嵌套方式存储呢,还是引用方式?

使用嵌套方式查询快,但是假如我要更新一个用户的头像网址怎么办?

如果使用引用方式,查询次数可能会有很多。

请大家指导一下,谢谢~

嵌套:

{ “post”: { “id”: 0, “content”: “content”, “comments”: [ { “author”: “author1”, “avator”: “http://…/a.jpg”, “comment”: “comment1” } ] }

引用:

{ “post”: { “id”: 0, “content”: “content”, }

{ “comment”: { “post_id”: “0”, “author”: “author1”, “avator”: “http://…/a.jpg”, “comment”: “comment1” } }


5 回复

Node.js 中 MongoDB 数据库设计:使用嵌套还是引用?

在设计 Node.js 应用程序中的 MongoDB 数据库时,经常会遇到是否应该使用嵌套文档还是引用外部文档的选择。这个问题的答案取决于你的具体需求以及你对性能、可维护性和扩展性的考虑。

嵌套 vs 引用

嵌套:当你有少量的、相对静态的数据,并且这些数据通常会被一起读取时,使用嵌套文档是一个不错的选择。这种方式可以减少查询次数,从而提高读取性能。

引用:当你需要频繁地更新或删除子文档,或者当子文档数量庞大时,使用引用的方式会更加灵活和高效。引用允许你在不影响其他数据的情况下独立更新子文档。

示例:博客评论系统

假设我们有一个博客系统,每个博客文章都可以有多个评论。我们来看看如何在这两种情况下实现它。

嵌套方式
const mongoose = require('mongoose');

const commentSchema = new mongoose.Schema({
    author: { type: String, required: true },
    avatar: { type: String, required: true },
    comment: { type: String, required: true }
});

const postSchema = new mongoose.Schema({
    id: { type: Number, required: true, unique: true },
    content: { type: String, required: true },
    comments: [commentSchema]
});

const Post = mongoose.model('Post', postSchema);
引用方式
const mongoose = require('mongoose');

const commentSchema = new mongoose.Schema({
    postId: { type: Number, required: true },
    author: { type: String, required: true },
    avatar: { type: String, required: true },
    comment: { type: String, required: true }
});

const Comment = mongoose.model('Comment', commentSchema);

// 在 Post 模型中引用 Comment
const postSchema = new mongoose.Schema({
    id: { type: Number, required: true, unique: true },
    content: { type: String, required: true }
});

postSchema.virtual('comments', {
    ref: 'Comment',
    localField: 'id',
    foreignField: 'postId'
});

const Post = mongoose.model('Post', postSchema);

总结

  • 嵌套方式适合于数据量小且不会经常变动的情况。例如,一个博客文章和少量的评论。
  • 引用方式更适合数据量大且需要频繁更新的情况。例如,一个用户头像的更新不需要影响所有相关的评论。

选择哪种方式取决于你的具体需求和应用场景。希望这些示例能帮助你做出更好的决策。


这个主要还是要根据你业务来看吧。 一、嵌套方法 有点:快速、高效、简单 缺点:需要定期去更新用户信息,这个频度不好把握。 现有的线上方案,如豆瓣用户的信息修改,是一个星期还是一个月只能修改一次(不太记得了)。所有可以采取这个方案,让用户不要频度太高的更新资料。 解决方案:有个服务定期去更新同步两个文档自己的相关信息。(例如:PV在凌晨3点最低的时候)

二、引用方式 优点:两个文档的数据同步更新。 缺点:查询耗时。如果是个频繁调用的功能,缺点会被放大。

建议: 考虑当前APP的体量和用户的特征。比如可以选择折中的方式,例如采用嵌套方式,可以更新头像时,将频繁调用的数据更新,一般的数据,放到后面定时更新等等。

[@vczero](/user/vczero) 非常详细,感谢!~

在Node.js中使用MongoDB进行数据库设计时,选择嵌套(内联)还是引用的方式取决于你的应用场景和性能需求。以下是一些考虑因素以及相应的代码示例。

嵌套方式

优点:

  • 查询速度快,因为数据都在同一个文档中。
  • 简化了数据的读取过程,不需要多次查询数据库。

缺点:

  • 更新一个子文档可能需要更新整个父文档,这会导致较大的写操作。
  • 数据冗余增加,可能导致数据一致性问题。

示例代码:

const mongoose = require('mongoose');

const commentSchema = new mongoose.Schema({
    author: String,
    avatar: String,
    comment: String
});

const postSchema = new mongoose.Schema({
    id: Number,
    content: String,
    comments: [commentSchema]
});

const Post = mongoose.model('Post', postSchema);

// 创建新的评论
const newComment = {
    author: 'author1',
    avatar: 'http://.../a.jpg',
    comment: 'comment1'
};

Post.findOneAndUpdate(
    { id: 0 },
    { $push: { comments: newComment } },
    { new: true }
).then(updatedPost => console.log(updatedPost))
.catch(err => console.error(err));

引用方式

优点:

  • 更灵活,可以独立更新子文档。
  • 减少数据冗余,提高数据一致性。

缺点:

  • 多次查询数据库以获取完整数据,性能可能稍差。
  • 需要处理多个查询的逻辑。

示例代码:

const mongoose = require('mongoose');

const commentSchema = new mongoose.Schema({
    postId: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' },
    author: String,
    avatar: String,
    comment: String
});

const Comment = mongoose.model('Comment', commentSchema);

// 创建新的评论
const newComment = new Comment({
    postId: mongoose.Types.ObjectId('somePostId'),
    author: 'author1',
    avatar: 'http://.../a.jpg',
    comment: 'comment1'
});

newComment.save()
.then(savedComment => console.log(savedComment))
.catch(err => console.error(err));

// 查询所有评论
Comment.find({ postId: mongoose.Types.ObjectId('somePostId') })
.then(comments => console.log(comments))
.catch(err => console.error(err));

总结

对于简单的场景,嵌套方式可以提供更好的性能。但对于复杂的应用,特别是当需要频繁更新子文档或减少数据冗余时,引用方式更为合适。根据实际需求选择适合的设计方案。

回到顶部