最近,闲着没事,又把上个月写得代码拿出来了,随便完善一下没完成的评论的路由接口。

评论应该是在整个博客数据存储中,模型最为复杂的一部分了。首先要考虑的是和文章进行关联。这个可以用 mongoDB 的 ref 进行关联,随后可以使用 populate 计算出被关联的字段。

最后关系复杂的是父子层级的评论,又或者是多级评论。这个时候就要想该怎么做才能合理的管理这些层级关系,在删除父评论的同时又能把所有子评论一起删除。查询的时候如何去由根到叶顺序输出层级关系。

建立评论模型

const schema = new mongoose.Schema({  // comment id  cid: {    type: Number,    required: true,    unique: true  },  // post id  pid: {    type: Number,    required: true  },  post: {    type: mongoose.SchemaTypes.ObjectId,    ref: 'Post'  },  content: {    type: String,    required: true  },  createTime: {    type: Number,    default: Date.now()  },  author: {    type: String,    required: true  },  owner: {    type: String,    required: true  },  isOwner: {    type: Boolean,    required: true  },  email: {    type: String  },  url: {    type: String  },  key: {    type: String,    required: true,    unique: true  },  parent: {    type: mongoose.SchemaTypes.ObjectId,    ref: 'Comment'  },  hasChild: { type: Boolean, default: false },  ipAddress: {    type: String,    required: true  },  userAgent: {    type: String  },  // 0 审核 1 发布 2 垃圾  state: {    type: Number,    required: true,    default: 0  }})

在模型中,post列中关联引用表(post表)的 _id(文章),在 hasChild 中记录是否存在回复。在后期处理回复路由的时候不要忘记修改他的值。最关键的是 key 列,这个用来记录平行层级。如 post 中的一篇 pid 为 11 的文章下有一条评论,那么 key 中命名 11#001,这是第一条评论,如果该评论下存在一条回复,则回复的 key11#001#001,下层亦是如此。使用该命名方式可以容纳的每条评论的回复量为 999,可以根据需求调整0的数量。

设定 Key 的意义

在建立记录的时候就把后期需要用到的slug直接生成,方便了前端的调用。这是一个原因。当然这不是重点,通过层次命名的 key,对删除父评论相当方便。例如下图所示的关系层级。

然后删除 key 为 11#001 的评论只要使用正则匹配 /^11#001/即可,把匹配到的内容全部删除就可以不用管关联的 post 是否一致,以及 cid,而 key 的值可以从前端发起的请求中提取 cid,用 cid 去查这个唯一记录,从中拿到我们需要的 key。

参考删除评论路由如下

router.delete('/', async (req, res) => {  const id = req.query.id  if (id) {    const isCid = id.length !== 24 ? true : false    try {      const query = await Comment.findOneAndDelete({        cid: id      }).populate('post')      if (query) {        if (query.hasChild) {          const delCount =          (await Comment.deleteMany({            key: new RegExp(`^${query.key}`, 'ig')          })).deletedCount + 1        }        await User.updateOne(        { username: req.username },        {          $inc: {            'options.comments_nums': -(delCount || 1)          }        }        )          // 删除post中的comments数量          query.post.comments -= delCount || 1          await query.post.save()}return res.send({ ok: 1, n: 1, deleteCount: delCount || 1 })} catch (e) {  console.log(e)  return res.send({ ok: 0, msg: '参数不正确' })}}return res.send({ ok: 0, msg: '请输入正确的ID' })})

说完了删除,相比之下新建评论就容易多了,只要根据原本的评论数量设定新的 key 就行了。可以使用模型提供的方法 countDocument()

const body = req.bodyconst comments = await Comment.countDocuments({      pid,      key: new RegExp(`^${pid}#\\d\\d\\d$`)    })body.key = String(pid) + `#${String(comments + 1).padStart(3, 0)}`

最后,看看数据库中的记录如何。

接口测试

初心者,一起学习,欢迎指出不足。
转载于我的博客 对博客中评论的合理建模 --MongoDB