记一次使用spring-data 查询mongodb,进行表关联的实现过程[aggregation,lookup,project,filter,cond]

背景

有两张表,简化为下面的结构:
课程 (course): courseNo,courseName,isDelete(用来逻辑删除)
试题(exam_question): courseNos,questionNo,questionDetail,isDelete(用来逻辑删除)
课程和试题是一对多的关系

其实如果用mongo的思想,应该把这两张表合二为一,试题是课程表的一个数组字段
如果没有试题的话,就是一个空数组
我这里是 原来只有课程,后来新加的试题,而且将来可能会改成课程和试题多对多的关系,也可能试题和别的都表关联,所以就独立两张表了
问题也不大,我们有lookup可以表关联

需要实现一个功能: 查询所有的课程,按照试题的数量排序
这里的核心难点在于,课程和试题都需要做一些筛选(isDelete=false)

本来想把思考的过程记录下来,包括错误的思路,后来想了想,没啥意义.
就只记录最终的正确思路了.

思路

如果是用SQL的话,这个很容易实现,直接搞个子查询,然后count一波
本着这个思路,我以课程表为基础,开始聚合(流水线)尝试:

  1. match,找到未删除的课程
  2. lookup,课程关联试题,通过字段 课程.courseNo 试题.courseNos,但是这里不能加筛选条件,而是把试题当成了一个字段(array)放到了课程下,起了个别名,叫做questions
  3. 这里为了筛选,比较曲折
    • (×)match,questions.isDelete=false 此路不通.因为match的主体是course,而非questions
    • (√)project+filter+cond,这样可以把questions筛选成所有isDelete=false
  4. project,只拿出我们想要的字段
    1~3步,我们拿到了{course,questions:[]},但是我只想要试题的数量,而不是所有的试题(减少网络IO)
    所以使用$size,只拿出试题的数量
  5. sort,skip,limit

其实如果第三步和第四步能够合并到一起的话,看起来会更好一点,即:在$size的时候添加一些$cond;但是目前没找到合适的语法.
将来如果找到更好的实现方式,再做优化.

结论

这里是aggregation的语法:

[
  {
    '$match': {
      'isDelete': false,
    }
  }, {
    '$lookup': {
      'from': 'ks_exam_question', 
      'localField': 'courseNo', 
      'foreignField': 'courseNos', 
      'as': 'questions'
    }
  }, {
    '$match': {
      'courseNo': {
        '$in': [
          '3f1f08dba2004576978c58e26a509465', '615e2afdb83b4b7085a4d2550ce633e3'
        ]
      }
    }
  }, {
    '$project': {
      'courseNo': '$courseNo', 
      'courseName': '$courseName', 
      'questions': {
        '$filter': {
          'input': '$questions', 
          'as': 'item', 
          'cond': {
            '$eq': [
              '$$item.isDelete', false
            ]
        
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值