文章的猫鼬模式

Mongoose schema for article

我正在建立一个新闻网站,我使用这个 mongoose 架构:

let mongoose = require('mongoose');

let articleSchema = mongoose.Schema({
  image1:{
    type: String,
    required: true
  },
  title:{
    type: String,
    required: true
  },
  author:{
    type: String,
    required: true
  },
  date:{
    type: String,
    required: true
  },
  updated:{
    type: String,
    default: 'not updated'
  },
  title_nd:{
    type: String,
    required: false
  },
  body:{
    type: String,
    required: true
  },
  comments: [commentsSchema],
  likes:{ type:Number, default:0 }
});

let Article = module.exports = mongoose.model('Article', articleSchema);

我想添加一个表单,以便用户可以添加他们的评论。 问题是如何为评论创建一个新的模式并将其 link 到文章模式,然后如果用户添加评论,评论将添加到数据库中,然后显示在文章评论部分?

根据我的拙见,为注释建模一个单独的模式并不是一个好主意,因为它是 one to few mapping 的经典案例,是嵌入文档的理想用例。为了让您对数据建模有一个基本的了解,我在这里引用

You need to consider two factors:

  • Will the entities on the “N” side of the One-to-N ever need to stand alone?
  • What is the cardinality of the relationship: is it one-to-few; one-to-many; or one-to-squillions?

Based on these factors, you can pick one of the three basic One-to-N schema designs:

  • Embed the N side if the cardinality is one-to-few and there is no need to access the embedded object outside the context of the parent object
  • Use an array of references to the N-side objects if the cardinality is one-to-many or if the N-side objects should stand alone for any reasons
  • Use a reference to the One-side in the N-side objects if the cardinality is one-to-squillions

请参考来自 mongodb 博客的 post 6 Rules of Thumb for MongoDB Schema Design: Part 1 一篇写得很好、表达清晰的文章。

即使在此之后,如果您认为 link 到另一个模式是个好主意,请参考这个 SO 问题 - Referencing another schema in Mongoose

所以我找到了解决方案:

// :id is all articles with all ids
router.post('/:id', function (req, res) {
  let comment = {};
  comment.body = req.body.body;
  comment.user = req.user;
  comment.date = new Date(Date.now()).toDateString();

  // Express validator
  req.checkBody('body').len(5, 100);

  let errors = [];
  errors = req.validationErrors();

  if(errors) {
    Article.findById(req.params.id, function (err, article) {
      if(err)throw err;
      req.flash('danger', 'Body minimum length is 5 and maximum 100!');
      res.redirect('/articles/'+article.id);
    });
  } else {
    Article.findById(req.params.id, function (err, article) {
      if(err)throw err;
     article.comments.push({'body':comment.body,'user':comment.user,'date':comment.date});
      article.save(function (err) {
        if (err) {
          throw err;
        }else {
          req.flash('success', 'Comment added!');
          res.redirect('/articles/'+article.id);
        }
      });
    });
  }
});

编辑:以上代码更易读:

router.post('/:id', async (req, res) => {
  let article = await Article.findById(req.params.id);

  if (!article) res.status("403");

  let articleUrl = "/articles/${article.id}";

  let comment = {
    body: req.body.body,
    user: req.user,
    date: new Date(Date.now()).toDateString();
  };

  if (commment.body.lengh >= 100 || comment.body.length <= 5) {
    req.flash('danger', 'Body minimum length is 5 and maximum 100!');
    return res.redirect(articleUrl);
  }

  articles.comments.push(comment);

  await article.save();

  req.flash('success', 'Comment added!');
  res.redirect(articleUrl);

});