【问题标题】:Understanding Mongoose sub documents了解 Mongoose 子文档
【发布时间】:2014-09-27 20:32:29
【问题描述】:

我正在学习猫鼬。目前我做了一些好事,但我真的不明白 Mongoose 如何管理 Schema 之间的关系。

所以,简单的事情(我希望):我正在做一个经典的练习(我自己做的,因为我找不到创建超过 2 个模式的好教程),其中包含 3 个模式:

用户、帖子、评论。

  • 用户可以创建多个帖子;
  • 用户可以创建多个评论;
  • 帖子属于用户。
  • 评论属于用户和帖子。

我不认为这是一件很难的事情吗?

目前我可以很好地管理用户和帖子之间的关系。我的单元测试返回的正是我所需要的,目前我正在使用mongo-relation,但我不知道这是否是个好主意......

  it('Use should create a Post', function(done) {
    User.findOne({ email: 'test@email.com' }, function(err, user) {
      var post = {
        title: 'Post title',
        message: 'Post message',
        comments: []
      };
      user.posts.create(post, function(err, user, post) {
        if (err) return done(err);
        user.posts[0].should.equal(post._id);
        post.author.should.equal(user._id);
        // etc...
        done();
      });
    });
  });

现在的问题是创建评论。 我无法创建同时引用帖子和用户的评论。

我做了类似的事情并且可以工作,但是当我执行 remove 时,它只会从帖子中删除,而不是从用户中删除。

所以我觉得有些东西我错过了,或者我仍然需要学习来增强它。

  it('User should add a Comment to a Post', function(done) {
    User.findOne({ email: 'test@email.com' }, function(err, user) {
      if (err) return done(err);

      var comment = new Comment({
        author: user._id,
        message: 'Post comment'
      });

      Post.findOne({ title: 'Post title'}, function(err, post) {
        if (err) return done(err);
        post.comments.append(comment, function(err, comment) {
          if (err) return done(err);

          post.save(function(err) {
            if (err) return done(err);
          });

          comment.author.should.equal(user._id);
          post.comments.should.have.length(1);
          // etc...
          done();
        });
      });
    });
  });

如您所见,代码不是很“好看”,但在创作方面效果很好。

问题是当我删除评论时。好像有什么不对。

这是模型关系:

// User Schema
var userSchema = new mongoose.Schema({
  // [...],

  posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }],
  comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }],

});

// Post Schema
var postSchema = new mongoose.Schema({
    author: { type: mongoose.Schema.ObjectId, ref: 'User', refPath: 'posts' },
    title: String,
    message: String,
    comments: [{ type: mongoose.Schema.ObjectId, ref: 'Comment' }]
});

// Comment Schema
var commentSchema = new mongoose.Schema({
    author: { type: mongoose.Schema.ObjectId, ref: 'User', refPath: 'comments' },
    post: { type: mongoose.Schema.ObjectId, ref: 'Post', refPath: 'comments' },
    message: String
});

我真的希望在你的帮助下理解这一切。

如果有一个简单的关于它的教程也会很好。

【问题讨论】:

  • 你如何删除它?

标签: javascript node.js mongodb express mongoose


【解决方案1】:

我认为您误解了子文档。您设置架构的方式是在创建对其他集合中文档的引用。

例如,如果您创建一个帖子,在数据库中它将如下所示:

{
  "author": ObjectId(123),
  "title": "post title",
  "message": "post message",
  "comments": [ObjectId(456), ObjectId(789)]
}

请注意,“作者”字段仅包含创建它的作者的 ID。它实际上并不包含文档本身。

当您从数据库中读取文档时,您可以使用 mongoose 的“填充”功能来获取引用的文档。

Ex(有填充):

Post
  .findOne({ title: 'Post title'})
  .populate('author', function(err, post) {
    // this will print out the whole user object
    console.log(post.author)
  });

Ex(无填充):

Post
  .findOne({ title: 'Post title'}, function(err, post) {
    // this will print out the object ID
    console.log(post.author)
  });

子文档:

您实际上可以使用子文档将数据嵌套在数据库中,架构看起来会略有不同:

 var postSchema = new mongoose.Schema({
   author: { userSchema },
   title: String,
   message: String,
   comments: [commentSchema]
 });

保存帖子时,用户文档将嵌套在帖子中:

{
  "author": { 
    "name": "user name",
    "email": "test@email.com"
    ...
  },
  "title": "post title",
  "message": "post message",
  "comments": [{
     "message": "test",
     ...
  }, {
     "message": "test",
     ...
  }]
}

子文档在 mongo 中可能很有用,但可能不适用于这种情况,因为您将在每个帖子中复制所有用户数据。

删除文档

当您发出 Comment.remove(id) 时,评论将被删除,但不会影响引用它的其他文档。因此,您将拥有一个帖子和一个用户,其评论 ID 不存在。您需要手动清除其他文档中的评论 ID。您可以使用 mongoose pre remove 事件来执行此操作。 http://mongoosejs.com/docs/middleware.html

commentSchema.pre('remove', function (next) {
  // this refers to the document being removed
  var userId = this.author;
  var postId = this.post;

  User.findById(userId, function(err, user) {

    // remove comment id from users.comments here;

    Post.findById(postId, function(err, post) {

      // remove comment id from post.comments;

      next();
    });
  });
});

【讨论】:

  • 我知道,我希望只拥有 ID,而不是复制整个用户文档...使用填充我可以获得我需要的所有属性。
  • 刚刚更新了我的答案,提供了一些有关删除文档的详细信息
  • 感谢您的更新,这很有意义,但是我如何从评论架构中获取用户 ID 和帖子 ID?你能提供一个更深入的例子吗?谢谢
  • 刚刚更新了我的答案,详细介绍了如何从被删除的评论中获取用户和帖子 ID
  • 谢谢你,非常感谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 2020-07-16
  • 1970-01-01
  • 2013-04-18
  • 2017-01-27
相关资源
最近更新 更多