当前位置:   article > 正文

MongoDB 之 aggregate $lookup 关联查询 进阶篇_mongodb aggregate lookup

mongodb aggregate lookup

 需求:要对 topics 问题表根据 teach_id(教师ID),tips._id(问题标签ID) 字段进行分组统计教师的答题情况生成报表,所以得根据 教师ID标签ID 关联查询出 教师信息标签信息 用作报表展示。

本文基于 MongoDB V3.2 聚合查询语法,V3.6 可使用更多的特性实现

topics 表数据结构:

  1. {
  2. "_id" : "ffffea46-ab7d-4c19-afa4-fe37709d5300",
  3. "evaluation_type" : 3,
  4. "type" : 3,
  5. "content" : "一般纳税人怎么结转成本",
  6. "tips" : [
  7. {
  8. "_id" : 1000,
  9. "tip_name" : "会计基础"
  10. }
  11. ],
  12. "update_at" : NumberLong("1469801351305"),
  13. "author_id" : 10334093,
  14. "timestamp" : NumberLong("1469714932097"),
  15. "race_time" : NumberLong("1469714947334"),
  16. "teach_id" : 10122995,
  17. "last_reply_content" : "这就要看你用的是什么成本计价方法。",
  18. "last_reply_at" : NumberLong("1469715279859"),
  19. "end_type" : 2
  20. }

 从数据结构中可以知道第一步操作是:

根据 teach_idtips._id 字段进行分组,可得 group(分组) 语句

  1. $group:{
  2. _id:{"teacherId":"$teach_id","tipId":"$tips._id"},
  3. evaluationTypes:{
  4. $push:"$evaluation_type"
  5. },
  6. sum: {$sum: 1}
  7. }

$push($push官方文档) 可以分组之后把 evaluation_type 字段值 赋给 evaluationTypes 加入到分组之后的返回值中

$sum($sum官方文档)可得到 teach_idtips._id 都相同的记录条数

使用脚本:

  1. db.getCollection("topics").aggregate([
  2. {
  3. $match:{
  4. "race_time" : {"$gte":1522512000000,"$lte":1525103999000},
  5. "type":3
  6. }
  7. },
  8. {
  9. $group:{
  10. _id:{"teacherId":"$teach_id","tipId":"$tips._id"},
  11. evaluationTypes:{
  12. $push:"$evaluation_type"
  13. },
  14. sum: {$sum: 1}
  15. }
  16. }
  17. ])

查询结果:

从结果可以看出 教师:10706280 在这个标签:1002 下一共抢答了 4 条问题,以及问题的 evaluationTypes(评价类型) 

一个分组作为报表的一条记录,所以我们得计算报表的总记录数(总行数)total,所以再对分好组的记录进行无条件分组(_id: null)

使用脚本:

  1. db.getCollection("topics").aggregate([
  2. {
  3. $match:{
  4. "race_time" : {"$gte":1525103910000,"$lte":1525103999000},
  5. "type":3
  6. }
  7. },
  8. {
  9. $group:{
  10. _id:{"teacherId":"$teach_id","tipId":"$tips._id"},
  11. evaluationTypes:{
  12. $push:"$evaluation_type"
  13. },
  14. sum: {$sum: 1}
  15. }
  16. },
  17. {
  18. $group:{
  19. _id: null,
  20. list:{
  21. $push:"$$ROOT"
  22. },
  23. total: {$sum: 1}
  24. }
  25. }
  26. ])

$$ROOT 指定的是分组前的所有数据,所以 list 会把第一次分组得到的数据都带上

total 是第一次分组之后的记录数,即一共分了多少组,之后用作分页总数

查询结果:

这里的 group 使用可参考:MongoDB 之 aggregate $group 巧妙运用

教师ID 以及 标签ID 等信息包含在 list 集合里,所以需要对 list 进行扁平化($unwind)操作,可参考:MongoDB 聚合嵌入的数组(扁平化数据+管道)

使用脚本:

  1. db.getCollection("topics").aggregate([
  2. {
  3. $match:{
  4. "race_time" : {"$gte":1522512000000,"$lte":1525103999000},
  5. "type":3
  6. }
  7. },
  8. {
  9. $group:{
  10. _id:{"teacherId":"$teach_id","tipId":"$tips._id"},
  11. evaluationTypes:{
  12. $push:"$evaluation_type"
  13. },
  14. sum: {$sum: 1}
  15. }
  16. },
  17. {
  18. $group:{
  19. _id: null,
  20. list:{
  21. $push:"$$ROOT"
  22. },
  23. total: {$sum: 1}
  24. }
  25. },
  26. {
  27. $unwind:"$list"
  28. },
  29. {
  30. $sort: {"list.sum": -1}
  31. },
  32. {
  33. $skip: 0
  34. },
  35. {
  36. $limit: 100
  37. }
  38. ])

 查询结果:

扁平化 list 集合数据之后,可根据 教师ID,标签ID 关联查询($lookup)出教师信息,标签信息

  1. $lookup:
  2. {
  3. from:"users",
  4. localField:"list._id.teacherId",
  5. foreignField: "_id",
  6. as: "users"
  7. }

$lookup(官方文档)3.2版本 只能根据 localField,foreignField 单条件关联,3.6版本中 关联查询引入 pipeline 管道支持更多更丰富的查询,对应本文会有更好的解决方案。具体使用可以查看官方文档

之后便是对数据的多次关联查询,以及扁平化操作,下面贴上完整查询脚本:

  1. db.getCollection("topics").aggregate([
  2. {
  3. $match:{
  4. "race_time" : {"$gte":1522512000000,"$lte":1525103999000},
  5. "type":3
  6. }
  7. },
  8. {
  9. $group:{
  10. _id:{"teacherId":"$teach_id","tipId":"$tips._id"},
  11. evaluationTypes:{
  12. $push:"$evaluation_type"
  13. },
  14. sum: {$sum: 1}
  15. }
  16. },
  17. {
  18. $group:{
  19. _id: null,
  20. list:{
  21. $push:"$$ROOT"
  22. },
  23. total: {$sum: 1}
  24. }
  25. },
  26. {
  27. $unwind:"$list"
  28. },
  29. {
  30. $sort: {"list.sum": -1}
  31. },
  32. {
  33. $skip: 0
  34. },
  35. {
  36. $limit: 100
  37. },
  38. {
  39. $lookup:
  40. {
  41. from:"users",
  42. localField:"list._id.teacherId",
  43. foreignField: "_id",
  44. as: "users"
  45. }
  46. },
  47. {
  48. $lookup:
  49. {
  50. from:"tip_content",
  51. localField:"list._id.tipId",
  52. foreignField: "_id",
  53. as: "childTip"
  54. }
  55. },
  56. {
  57. $lookup:
  58. {
  59. from:"tip_content",
  60. localField:"childTip.parent_tip_id",
  61. foreignField: "_id",
  62. as: "parentTip"
  63. }
  64. },
  65. {
  66. $unwind:"$users"
  67. },
  68. {
  69. $unwind:"$childTip"
  70. },
  71. {
  72. $unwind:"$parentTip"
  73. },
  74. {
  75. $project:{
  76. "teacherId":"$list._id.teacherId",
  77. "teacherName":"$users.real_name_from_nc",
  78. "tuid":"$users.tuid",
  79. "mobile":"$users.mobile",
  80. "tipId":"$childTip._id",
  81. "tipName":"$childTip.tip_name",
  82. "parentTipId":"$parentTip._id",
  83. "parentTipName":"$parentTip.tip_name",
  84. "sum":"$list.sum",
  85. "total":"$total",
  86. "evaluationTypes":"$list.evaluationTypes",
  87. "_id":0
  88. }
  89. }
  90. ])

查询结果:

 reference:

mongo-java-driver javadoc

Mongodb 3.2 Java 显示指定字段 条件查询 官方

Java MongoTemplate查询返回指定字段及指定数量的数据

java 操作mongoB只查询指定字段

mongodb学习总结(二)

java操作mongodb——查询数据

Mongoexport error parsing query

关注公众号,分享干货,讨论技术,你的支持是我最大的动力!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56021
推荐阅读
相关标签
  

闽ICP备14008679号