使用 mongoose 对子子文档进行 CRUD

Posted

技术标签:

【中文标题】使用 mongoose 对子子文档进行 CRUD【英文标题】:Doing CRUD on sub-sub-documents using mongoose 【发布时间】:2016-08-27 22:30:11 【问题描述】:

我是学习 MEAN 堆栈的初学者,我正在尝试建立一个基本论坛以熟悉此堆栈。到目前为止,除了 sub-sub-docs 之外,我已经完成了所有工作。我在主题内的帖子中对 cme​​ts 执行 CRUD 时遇到问题。我已经做了很多搜索,但没有任何东西看起来完全符合我的需要。所以我的问题是,你将如何实现这一点?我知道可能有多种方法可以做到这一点,例如使用 refs 而不是子子文档,但是看到我已经为 CRUD 主题和使用子文档的主题中的 CRUD 帖子等内容编写了代码,我会如果我必须回去更改我的代码,而不是使用 refs。

var express = require('express');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var uri = "...";
mongoose.connect(uri);

var CommentSchema = new Schema(
  id: ObjectId,
  content: String,
  author: UserSchema
);

var PostSchema = new Schema(
  id: ObjectId,
  title: String,
  author: UserSchema,
  comments: [CommentSchema]
);

var TopicSchema = new Schema(
  id: ObjectId,
  title: String,
  moderator: UserSchema,
  posts: [PostSchema]
);

var Topic = mongoose.model('Topic', TopicSchema);

var app = express();

app.delete('/topics/:topicId/posts/:postId/comments/:commentId', function(req, res) 
    //What goes here?
);

app.put('/topics/:topicId/posts/:postId/comments/:commentId', function(req, res) 
    //What goes here?
);

app.post('/topics/:topicId/posts/:postId/comments/:commentId', function(req, res) 
    //What goes here?
);

app.get('/topics/:topicId/posts/:postId/comments/:commentId', function(req, res) 
    //What goes here?
);

【问题讨论】:

【参考方案1】:

我建议不要将您的对象嵌入得太深。也许创建一个评论集合,它会更方便。 无论如何,如果你想使用一个 mongoose 操作,你必须先遍历帖子,才能知道要更新的索引。让我们假设它是 0,删除评论:

Topic.findOneAndUpdate(
   id: req.params.topicId ,
   $pull:  'posts.0.comments':  _id: req.params._id  ,
   safe: true 
)

这就是为什么它不是你真正想要的。

您可以直接更改对象并保存它:

Topic.findOne( _id: req.params.topicId )
  .then(topic => 

    const  posts  = topic
    let comments
    for (let i = 0, l = posts.length; i < l; ++i) 

      if (posts[i]._id.toString() === req.params.postId) 
        comments = posts[i].comments
        for (let j = 0, m = comments.length; j < m; ++j) 
          if (comments[j]._id.toString() === req.params.commentId) 
            comments.splice(j, 1)
            break
           
        )

        break
      

    

    return topic.save()
  )

不是很理想,因为它没有利用 mongodb 索引和研究来进行这些操作。但你可以使用:

const CommentSchema = new Schema(
  id: ObjectId,
  postId: ObjectId,
  content: String,
  author: UserSchema
)

const Comment = mongoose.model('Comment', CommentSchema)

Comment.findOneAndUpdate( id: req.params.commentId, postId: req.params.postId ,  ... )

【讨论】:

app.put('/topics/:topicId/posts/:postId/cmets/:commentId', requireLogin, function(req, res) var topicId = req.params.topicId; var postId = req.params.postId; var commentId = req.params.commentId; User.findOne("email": req.session.user.email, function(err, user) if (user.role == "user " || user.role == "admin") Topic.findById(topicId, function(err, topic) topic.posts.id(postId).cmets.id(commentId).content = req.body.content; topic.save(function(err) if (err) console.log(err); res.status(204).end(); ); ); ); ); 但是,我认为您给出的最后一个示例似乎是最优雅和最直接(并且可能也是有效)的方法,所以我可能会改用它。

以上是关于使用 mongoose 对子子文档进行 CRUD的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 模式——对子文档使用对象而不是数组

Mongoose 模式——对子文档使用对象而不是数组

猫鼬中的 findOne 子文档

猫鼬中的 findOne 子文档

无法“跳过”猫鼬子文档

猫鼬引用子文档的不同方式?