1

1、首先我们先在model目录下新建comment.js文件,这里使用egg-mongoose进行配置表以及字段,这里关键需要parent_id作为父级字段,若默认为0则是第一级评论,如果为id,则是二级评论。

'use strict';

/**
 * @description: Mongoose comment Schema,
 */

module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;
  const CommentSchema = new Schema({
    from: { /* 评论人id */
      type: Schema.Types.ObjectId,
      ref: 'User',
    },
    to: { /* 被评论人id */
      type: Schema.Types.ObjectId,
      ref: 'User',
    },
    content: { type: String }, /* 内容 */
    create_time: { type: String }, /* 评论时间 */
    book: { /* 书籍id */
      type: Schema.Types.ObjectId,
      ref: 'Book',
    },
    parent_id: { type: String, required: true, default: 0 } /* 父级 */
  });
  return mongoose.model('Comment', CommentSchema);
};

2、在controller 目录下新建comment.js 用于编写 评论相关的控制器方法,这里我定义了新增评论和查询评论,使用egg-validate进行请求参数验证如下:

'use strict';

const Controller = require('egg').Controller;
// 定义新增评论请求参数规则
const createCommentRule = {
  from: 'string',
  to: {
    type: 'string',
    required: false,
  },
  content: 'string',
  book: 'string',
  parentId: {
    type: 'string',
    required: false,
  },
}
// 定义查询评论请求参数规则
const findCommentRule = {
  book: 'string',
  page: 'string',
  pageSize: 'string'
}
class CommentController extends Controller {
  async create() {
    const { ctx } = this;
    ctx.validate(createCommentRule, ctx.request.body);
    const result = await this.ctx.service.comment.createComment(ctx.request.body);
    ctx.body = result;
  }
  async find() {
    const { ctx } = this;
    ctx.validate(findCommentRule, ctx.query);
    const result = await this.ctx.service.comment.findComment(ctx.query);
    ctx.body = result;
  }
}

module.exports = CommentController;

在对应的控制器方法调用service层里面的方法,在service的方法进行数据库操作与逻辑处理。

3、在service目录下新建comment.js用于编写评论相关service方法。如下:

'use strict';

/**
 * @description: 评论相关Service
 */
const Service = require('egg').Service;
const mongoose = require('mongoose');
const dayjs = require('dayjs');
module.exports = app => {
  class CommentService extends Service {
    /**
     * 新增评论
     * @param  {Object} data 包括评论人id,被评论人id,书籍id, 评论父级id,评论内容
     */
    async createComment(data) {
      const { from, to, content, book, parentId } = data;
      const result = await this.ctx.model.Comment.create({
        from,
        to,
        content,
        book,
        parent_id: parentId ? mongoose.Types.ObjectId(parentId) : 0,
        create_time: dayjs().unix(),
      });
      return result ? app.config.msg.CREARE_SUCCESS : app.config.msg.CREARE_ERR;
    }
    /**
     * 查询评论
     * @param  {Object} data 包括书籍id,页码,页数
     */
    async findComment(data) {
      const { book, page, pageSize } = data
      const totalNum = await this.ctx.model.Comment.find({ book: mongoose.Types.ObjectId(book), parent_id: 0 }).countDocuments();
      const oneList = await this.ctx.model.Comment.find({ book: mongoose.Types.ObjectId(book), parent_id: 0 })
        .populate({
          path: 'from',
          select: { name: 1, image: 1, _id: 1 }
        })
        .populate({
          path: 'to',
          select: { name: 1, image: 1, _id: 1 }
        })
        .sort({ create_time: 1})
        .skip((parseInt(page) - 1) * parseInt(pageSize))
        .limit(parseInt(pageSize)).lean();
        const Comment = this.ctx.model.Comment
        var promises = oneList.map(item => {
          return Comment.find({
              book: mongoose.Types.ObjectId(book),
              parent_id: item._id
          })
          .populate({
            path: 'from',
            select: { name: 1, image: 1, _id: 1 }
          })
          .populate({
            path: 'to',
            select: { name: 1, image: 1, _id: 1 }
          })
          .sort({ create_time: 1})
          .select('-__v').lean()
      });
      var list = await Promise.all(promises)
      oneList.forEach(item => {
        item.items = []
        list.forEach(code => {
          if (code.length > 0 && item._id == code[0].parent_id) {
              item.items = code
          }
        })
      })
      return oneList ? { bean: {
        records: oneList,
        current: page,
        size: oneList.length,
        total: totalNum,
      }, ...app.config.msg.GET_SUCCESS } : app.config.msg.GET_ERR;
    }
  }
  return CommentService;
};

注:首先我们需要查询一级评论的分页数据,然后用map遍历一级评论列表,返回一个promises数组,数组的每一项是查询该一级评论下的所有二级评论,我这里没有进行分页,也可以加上分页。使用Promise.all异步执行所有的查询函数,完成后的结果赋值为list,最后遍历一级评论列表与二级评论列表,当一级评论id 等于 二级评论列表中parent_id时候 给当前一级评论列表增加 items属性用于存放它的二级评论。

最后在router.js中定义接口路径与请求类型,如下:

  // 新建评论
  router.post('/api/comment/create', controller.comment.create);
  // 查询评论
  router.get('/api/comment/find', controller.comment.find);

YoLinDeng
545 声望520 粉丝

等到秋叶终于金黄,等到华发悄然苍苍。


引用和评论

0 条评论