了解Mongoose子文档

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

所以,容易的事情(我希望):我正在做一个经典的练习(我自己,因为我找不到一个很好的教程,创build超过2个模式)与3个模式:

用户,发布,评论。

  • 用户可以创build多个Post;
  • 用户可以创build很多评论;
  • post属于用户。
  • 评论属于用户和post。

我不认为这是非常难呃?

目前我可以很好地pipe理用户和邮政之间的关系。 我的unit testing返回正是我所需要的,此刻我正在使用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(); }); }); }); 

现在的问题是创build一个评论。 我无法创build一个引用邮件和用户的评论。

我做了这样的工作,但工作,但是当我执行一个remove它只能从post,而不是从用户删除。

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

  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 }); 

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

这也将是一个简单的好教程。

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

例如,如果你创build一个post,在数据库中它将看起来像这样:

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

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

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

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] }); 

保存post时,用户文档将嵌套在post内:

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

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

删除文件

当您发出Comment.remove(id)时,注释将被删除,但不会影响引用它的其他文档。 所以你将有一个post和一个用户的评论ID不存在。 您需要手动清理其他文档中的评论ID。 你可以使用mongoose预删除事件来做到这一点。 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(); }); }); });