查看原文
其他

最佳实践丨云数据库实现联表+聚合查询

云开发团队 腾讯云云开发CloudBase 2021-05-15

聚合开发 CloudBase 数据库中非常重要的一种数据批处理操作方式聚合操作可以将数据分组(或者不分组,即只有一组/每个记录都是一组),然后对每组数据执行多种批处理操作,最后返回结果。

有了聚合能力,可以方便的解决很多没有聚合能力时无法实现或只能低效实现的场景,包括分组查询、只取某些字段的统计值或变换值返回、流水线式分阶段批处理、获取唯一值(去重)等

本文就以一个简单的实例解释如何在云数据库中,实现十分常用的联表+聚合查询操作。

场景说明

假设数据库内存在两个集合:class  student存在以下数据:

class(班级信息)

student(学生信息)

现在需要查询徐老师所带的班级里面所有学生的平均成绩。

代码示例

1、lookup 联表查询

首先我们需要把 student 内的所有数据,按照 class_id 进行分组,这里我们使用云数据库的 lookup 操作符
lookup({ from: "student", //要关联的表student localField: "id", //class表中的关联字段 foreignField: "class_id", //student表中关联字段 as: "stu" //定义输出数组的别名}).end();

这个语句会查出来下面的结果,会查出班级的信息以及该班级所对应的所有学生的信息:
{"list": [{ "id":1, "teacher":"王老师", "cname":"一班", "stu":[ { "sname":"宁一", "class_id":1, "score":90 } ] }, { "id":2, "teacher":"徐老师", "cname":"二班", "stu":[ { "class_id":2, "sname":"张二", "score":100 }, { "class_id":2, "sname":"李二", "score":80 } ] }]}

但是我们只需要徐老师所在班级学生的数据,所以需要进一步过滤。


2、match 条件匹配

.lookup({ from: 'student', localField: 'id', foreignField: 'class_id', as: 'stu'}).match({ teacher:"徐老师"}).end()

现在就只是返回徐老师所在班级的学生数据了,学生数据在 stu 对应的数组里面:
{ "list": [ { "_id": "5e847ab25eb9428600a512352fa6c7c4", "id": 2, "teacher": "徐老师", "cname": "二班", //学生数据 "stu": [ { "_id": "37e26adb5eb945a70084351e57f6d717", "class_id": 2, "sname": "张二", "score": 100 }, { "_id": "5e847ab25eb945cf00a5884204297ed8", "class_id": 2, "sname": "李二", "score": 80 } ] } ]}

接下来我们继续优化代码,直接返回学生的平均分数。


3、直接返回学生成绩平均值

如果想要在被连接的表格中(本课程中的 student)做聚合操作,就用 pipeline 方法:
.lookup({ from: 'student', pipeline: $.pipeline() .group({ _id: null, score: $.avg('$score') }) .done(), as: 'stu'}).match({ teacher:"徐老师"}).end()

现在输出的数据是这样的:
{ "list": [ { "_id": "5e847ab25eb9428600a512352fa6c7c4", "id": 2, "teacher": "徐老师", "cname": "二班", "stu": [{ "_id": null, "score": 90 }] } ]}


但是现在输出的数据有点复杂,如果只想显示 teacher 和 score 这两个值,我们再进行下面的操作。

4、只显示 teacher 和 score 这两个值

我们使用 replaceRootmergeObjects 和 project 进行最后的处理:

.lookup({ from: 'student', pipeline: $.pipeline() .group({ _id: null, score: $.avg('$score') }) .done(), as: 'stu'}).match({ teacher:"徐老师"}).replaceRoot({ newRoot: $.mergeObjects([$.arrayElemAt(['$stu', 0]), '$$ROOT'])}).project({ _id:0, teacher:1, score:1}).end()

现在输出的数据是这样的:

{ "list": [{ "score": 90, "teacher": "徐老师" }] }

相关文档:云开发聚合搜索
https://docs.cloudbase.net/database/aggregate.html



</>
Q&A

还想看到哪些云开发的最佳实践?

欢迎在评论区留言~







      点击在看让更多人发现精彩

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存