本文最后更新于:
2022年10月10日 下午
[toc]
问题描述
现在我有一个这样的 mongodb 文档模型 Article
author、group
这两个字段分别左外部联接 User
和ArticleGroup
两个集合
我使用的是 mongoose 对象文档模型(ODM)库,集合名称都是大写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const ArticleSchema = new mongoose.Schema({ title: { type: String, required: true }, author: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }, group: { type: mongoose.Schema.Types.ObjectId, ref: "ArticleGroup" }, });
const ArticleGroupSchema = new mongoose.Schema({ name: { type: String, required: true }, desc: { type: String, default: "" }, state: { type: String, required: true, default: "public" }, members: [ { desc: String, role: String, user: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }, }, ], });
const userSchema = new mongoose.Schema( { email: { type: String, unique: true }, password: String, }, );
|
test data :
1 2 3 4 5 6
| { _id: "6131aa5b367318e2df14b988", title: "功能更新清单", author: ObjectId("607edeb4b1e1bea9acb5af38"), group: ObjectId("612d00a43c52975d4ade10d4") }
|
我预期的结果
我想在 aggregate 聚合操作内通过比较 author._id == group.members.user 的值,向文档添加一个新字段 can_edit。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Article.aggregate([ { $lookup: { from: "users", localField: "author", foreignField: "_id", as: "author", }, }, { $lookup: { from: "articlegroups", localField: "group", foreignField: "_id", as: "group" } }, { $addFields: { can_edit: { $eq: ["$group.members.user", "$author._id"], }, } } ])
|
可是我得到的 can_edit 值始终是 false,我确定在我的测试数据中 author._id 的值和group.members.user 是相同。
期望返回的文档结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| { _id: "6131aa5b367318e2df14b988", can_edit: true, title: "功能更新清单", author: { _id: "607edeb4b1e1bea9acb5af38", email: "frmachao@126.com", }, group: { _id: "612d00a43c52975d4ade10d4", desc: "开发", state: "public", name: "开发小组", members: [ { _id: "612d00a43c52975d4ade10d5", role: "admin", user: "607edeb4b1e1bea9acb5af38", } ] } }
|
刚刚,我找到一个相似的问题 stackoverflow。上面提到: $eq (聚合)比较不同于查询 eq opeator 的值和类型,后者可以比较任何类型的值。需要 $in (聚合)来验证数组中的值
于是我尝试做了下面更改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Article.aggregate([ { $lookup: { from: "users", localField: "author", foreignField: "_id", as: "author", }, }, { $lookup: { from: "articlegroups", localField: "group", foreignField: "_id", as: "group" } }, { $addFields: { can_edit: { $in: [ "$author._id", "$group.members.user" ], }, }, } ])
|
但是遇到了新问题: $in requires an array as a second argument
在挣扎了100分钟: 尝试用搜索引擎检索我遇到的问题、去翻阅$eq聚合阶段
的文档、咨询微信里做过服务端开发的网友
可是问题还是没有解决,最后我决定去社区提问。
去社区提问
- 国内 segmentfault
- 国外的 stackoverflow
mongoplayground
stackoverflow 上面,一位热心的马来西亚程序员帮我解决了问题:
他告诉我 应该 group.members must be array checking
,也就是先要判断group.members 是不是一个数组。
分析:在我定义的数据模型里,group 并不是一个必填项,所以 group 字段可能为空
1 2 3 4 5
| const ArticleSchema = new mongoose.Schema({ title: { type: String, required: true }, author: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }, group: { type: mongoose.Schema.Types.ObjectId, ref: "ArticleGroup" }, });
|
热情的马来西亚程序员 甚至给出了完整的 判断 group.members must be array 的样例,附上调试地址,respect!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| db.collection.aggregate([ { $addFields: { can_edit: { $switch: { branches: [ { case: { $ne: [ { "$type": "$group.members" }, "array" ] }, then: false }, { case: { $ne: [ { "$type": "$group.members" }, "array" ] }, then: false }, { case: { $in: [ "$author._id", "$group.members.user" ] }, then: true } ], default: false } } } } ])
|
收获
- mongoplayground一个网站 可以在线调试 mongoDB的查询
- $eq (聚合)比较不同于查询 eq opeator 的值和类型,后者可以比较任何类型的值。需要 $in (聚合)来验证数组中的值。
- 去社区提问需要注意:描述清楚自己的问题,不要带上自己的业务细节把问题剥离出来,最好能提供一个在线运行的
playground
。
🤔思考
- 自学能力差: 为什么我翻看文档时没有看到
$eq (聚合)比较不同于查询 eq opeator 的值和类型,后者可以比较任何类型的值。需要 $in (聚合)来验证数组中的值
- 英语很差:stackoverflow 上编写的提问描述全部来自 google 翻译 中–》英