一:需求场景
我的个人网站留言列表在开发时,因为本着先有功能的原则。留言列表只有一级,平铺的。
当涉及多人回复,或者两个人多次对话后, 留言逻辑看着非常混乱。如下图
于是,我就打算将平铺的列表,改造为二级列表。效果图如下
二:实现方案
因为我是前端开发,对数据库查询语言的认知还停留在
select * from table
我对数据库的使用,之前真真就是把它当个持久存放数据的仓库。查询语句都停留在最简单的增删改查。
于是我在考虑如何实现功能时,第一个想法又是,在原有表结构的基础上添加一个parent字段。
如果是顶级留言parent字段存放空值,二级或者三级都存放父级的id。
然后接口返回数据给前端,前端JS再把数据处理两级的结构。虽然个人网站的前后端都是我自己。但是还是感觉JS更加顺手
后来考虑到存在分页,如上方案是解决不了分页问题的。
三: 数据库查询语句
因为后端是用Node.js配合MongoDB开发的,于是去查了查用Mongodb的查询语句直接完成两级结构。
然后我打开了一个新世界的大门~~~
数据库的查询语句可比JS在哪处理数据的效率高上几个维度,如下为使用Mongodb的管道聚合的查询语句。一个语句搞定JS无数个循环,且逻辑清晰!
DB.collection(Collection).aggregate([
{
$sort: {
_id: -1 // 先按时间倒序排序
}
},
{
$lookup: { // 将子留言与其父级文档关联,将自留言的集合作为父留言的一个字段
from: Collection,
localField: "_id",
foreignField: "parentId",
as: "son"
}
},
{
$match: { // 只留下顶级评论
parentId: { $in: ["", null] }
}
},
{
$skip: data.Skip // 跳过(page-1)*page_size条文档数,供分页使用
},
{
$limit: data.Limit// 限制返回的文档数为page_size,供分页使用
}
])
四:Mongodb的管道聚合
Mongodb中管道通常由多个阶段构成,每个阶段由一个操作和它的参数组成,如 $match、$project、$sort、$group 等。
这些阶段按照代码书写顺序执行,每一个阶段输出都是它下一个阶段的输入,所有阶段的输出结果最终形成管道的最终输出。