评论

【笔记】云开发聚合实现分页,涉及跨表查询、逻辑计算、判断权限、数据格式化、限制输出

云开发聚合实现分页查询,涉及到跨表查询、逻辑计算、判断权限、限制输出。

背景:

之前不会用聚合,因此把数据库结构分为了用户表、帖子表、喜欢表。
小程序端请求一次列表,要根据帖子列表,循环查询用户表,并且还要做一系列的逻辑运算处理,计算当前帖子的权限、是否喜欢过、喜欢人数、是否有这个帖子管理权限等信息。

这样做有很多弊端:

  1. 处理速度慢,资源耗费严重,循环查询肯定慢且耗费资源,一个列表需要21次查询。
  2. 需要写大量逻辑处理代码,如计算管理权限,喜欢数量、当前用户是否喜欢,格式处理等等。

于是使用聚合进行了优化:

  1. 跨表查询
  2. 数据格式化
  3. 逻辑计算,权限判断、是否喜欢等
  4. 数据统计,喜欢总人数
  5. 权限判断,是否为管理员
  6. 限制输出

效果:

之前:上百行代码,多次查询,需要单独判断函数,处理时间在3000ms以上
之后:几行代码,一次查询,直接查询时算出结果,处理时间在300ms以内


数据库结构

代码实现:

  const { OPENID } = cloud.getWXContext(context)
//构建查询条件
  let query = null
  switch (Number(event.listType)) {
    case 0:
      query = db.collection('post').aggregate()
        .match({
          //0我的
          '_openid': OPENID
        })
        .sort({
          createTime: -1
        })
        .skip(20 * (event.pageNum - 1))
        .limit(20)


      break;
    case 1:
      //1 随机
      query = db.collection('post').aggregate()
        .match({
          public: true,
          // feeling: _.gte(50)
        })
        .sample({
          size: 20
        })


      break;
    case 2:
      query = db.collection('post').aggregate()
        .match({
          //2喜欢
          likes: _.all([OPENID])
        })
        .sort({
          createTime: -1
        })
        .skip(20 * (event.pageNum - 1))
        .limit(20)


      break;
    case 4:
      query = db.collection('post').aggregate()
        .match({
          //4指定
          _id: event.id
        })
        .sort({
          createTime: -1
        })
        .skip(20 * (event.pageNum - 1))
        .limit(20)


      break;
  }


  //使用聚合处理后续数据
  let listData = await query
    .lookup({
      from: "user",
      localField: "_openid",
      foreignField: "_id",
      as: "postList"
    })//联表查询用户表
    .replaceRoot({
      newRoot: $.mergeObjects([$.arrayElemAt(['$postList', 0]), '$$ROOT'])
    })//将用户表输出到根节点
    .addFields({
      day: $.dayOfMonth('$createTime'),
      month: $.month('$createTime'),
      year: $.year('$createTime'),
      isLike: $.in([OPENID, '$likes']), //是否喜欢
      isLiked: $.in([OPENID, '$liked']), //是否喜欢过
      isAdmin: $.eq([OPENID, 'oy0T-4yk7lCRFGDefpFC4Yvx_ppU']),//是否管理员
      isAuthor: $.eq(['$_openid', OPENID]),//是否为作者
      like: $.size('$likes'), //喜欢该帖子数
      face: $.switch({
        branches: [
          { case: $.gte(['$feeling', 90]), then: 9 },
          { case: $.gte(['$feeling', 80]), then: 8 },
          { case: $.gte(['$feeling', 70]), then: 7 },
          { case: $.gte(['$feeling', 60]), then: 6 },
          { case: $.gte(['$feeling', 50]), then: 5 },
          { case: $.gte(['$feeling', 40]), then: 4 },
          { case: $.gte(['$feeling', 30]), then: 3 },
          { case: $.gte(['$feeling', 20]), then: 2 },
          { case: $.gte(['$feeling', 10]), then: 1 }
        ],
        default: 0
      }) //根据心情值判断对应表情
    })
    .project({
      postList: 0,
      userInfo: 0,
      liked: 0,
      likes: 0,
      city: 0,
      province: 0,
      country: 0,
      language: 0,
      nlp: 0,
      saveType: 0,
    }) //清楚掉不需要的数据
    .end()


    return listData
最后一次编辑于  05-26  
点赞 1
收藏
评论

3 个评论

  • Admin²⁰²⁰
    Admin²⁰²⁰
    05-14

    这个不错,可以加社区精华

    05-14
    赞同 1
    回复
  • yh
    yh
    2天前

    喜欢这个帖子的动作你是把用户id加到这个帖子的likes字段的,那如果是一个爆贴,喜欢的人很多,是不是会导致数据量很大,这个怎么处理?


    2天前
    赞同
    回复 2
    • 驰子
      驰子
      22小时前
      project({likes:0}),输出的时候限制。
      22小时前
      回复
    • yh
      yh
      19小时前回复驰子
      我不是这个意思,我的意识是
      你的post这张表,里边的like字段是一个数组,如果有一万个人喜欢,那么这个数组长度就是一万,这样的话会不会有影响
      19小时前
      回复
  • 文
    05-29
    .! ∵? !::∴
    05-29
    赞同
    回复
登录 后发表内容