最近有个需求,用 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 环境,我们熟悉的箭头函数、异步函数等都可以放心使用,所以写起来大约是这样:
mongoose// 进入聚合状态 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 作为也有不短的历史,搜索得到的内容覆盖很多版本,很难直接应用
希望将来能慢慢克服这些难点。欢迎诸位读者指教,如有问题,也欢迎提出讨论。
欢迎吐槽,共同进步