最近有个需求,用 SQL 描述起来大约是这样的:
# pages 表按照 projectId 统计每个 project 的页面数
# 然后更新到 projects 表的 `pageCount` 字段里
UPDATE `projects` a LEFT JOIN
(
SELECT COUNT('x') as `num`, `projectId`
FROM `pages`
WHERE `isDeleted`=false
GROUP BY `projectId`
) b
ON a.`_id`=b.`projectId`
SET `pageCount`=`num`
WHERE a.`isDeleted`=false
# 上面 SQL 凑合看,我好久不写了,有点忘记怎么写……
MongoDB Shell 其实就是封装好的 JavaScript + Node.js 16 REPL 环境,我们熟悉的箭头函数、异步函数等都可以放心使用,所以写起来大约是这样:
// 进入聚合状态
db.projects.aggregate([
// 聚合状态会从上至下执行,所以我们先筛选出来合适的 projects
{
$match: {
creatorId: '我的用户id',
isDeleted: false,
kind: 'Normal',
},
},
// 因为我厂 pages 表里 projectId 是字符类型,所以这里要先转换一次
{
$addFields: {
projectId: { '$toString': '$_id'},
}
},
// 接下来就可以聚合了,用本地的 projectId 对上连表的 projectId,连起来之后的字段名为 pages,它应该是个数组
{
$lookup: {
from: 'pages',
localField: 'projectId',
foreignField: 'projectId',
as: 'pages',
}
},
// 再添加一个字段用来存储 pages 的长度,即有多少个页面,这里要加 `$` 前缀
{
$addFields: {
pageCount: {
$size: '$pages'
}
}
}
])
// 聚合完毕之后,再把内容写入数据库
.forEach(doc => {
db.projects.updateOne({ _id: doc._id}, {
$set: { pageCount: doc.pageCount }
})
});
对于我来说,操作 mongosh 的难点主要在于:
- 很多时候要加
$
前缀,一会儿一个一会儿两个,不熟悉经常搞错 - 不知道是否该用异步函数或者
.then()
- 不知道
$addFields
函数 - 没法打断点调试,需要一长串执行完才知道结果
- MongoDB 作为也有不短的历史,搜索得到的内容覆盖很多版本,很难直接应用
希望将来能慢慢克服这些难点。欢迎诸位读者指教,如有问题,也欢迎提出讨论。
欢迎吐槽,共同进步