Mongoose嵌套populate的select不生效:post_comments仍显示_id与__v
问题
我有Post、User、Comment三个Mongoose Schema,结构如下:
postSchema = mongoose.Schema({ post_title, post_description, post_timestamp, post_author:{ type:mongoose.Schema.Types.ObjectId, ref: "User" }, post_likes:{ type: [userSchema.schema] }, post_comments:{ type: [commentSchema.schema] } })
userSchema = mongoose.Schema({ username, email, password, date })
commentSchema = mongoose.Schema({ comment_description, comment_timestamp, comment_author:{ type:mongoose.Schema.Types.ObjectId, ref: "User", require:true, } })
我希望查询返回的Post数据里,post_comments数组中的每个评论对象移除_id和__v字段,期望格式如下:
{ "_id": "638bdf38b2ad86abe32455fd", "post_title": "This is a test post", "post_description": "abc...", "post_timestamp": "2022-12-03T23:41:04.292Z", "post_author": { "username": "test10" }, "post_comments": [ { "comment_description": "This is my first comment for this new post", "comment_timestamp": "2022-12-03T23:51:24.306Z", "comment_author": { "username": "test10" } }, { "comment_description": "This is my first comment for this new post", "comment_timestamp": "2022-12-04T10:06:22.091Z", "comment_author": { "username": "test11" } } ] }
但实际返回的post_comments仍包含_id和__v,格式如下:
{ "_id": "638bdf38b2ad86abe32455fd", "post_title": "This is a test post", "post_description": "abc...", "post_timestamp": "2022-12-03T23:41:04.292Z", "post_author": { "username": "test10" }, "post_comments": [ { "comment_description": "This is my first comment for this new post", "comment_timestamp": "2022-12-03T23:51:24.306Z", "comment_author": { "username": "test10" }, "_id": "638be126b9fe7d1b4823882c", "__v": 0 }, { "comment_description": "This is my first comment for this new post", "comment_timestamp": "2022-12-04T10:06:22.091Z", "comment_author": { "username": "test11" }, "_id": "638c738ab63be98a89d2cb76", "__v": 0 } ] }
我用的查询代码如下:
const posts = await Post.find({}, { post_title: 1, post_description: 1, post_timestamp: 1 }) .populate({ path: "post_author", model: "User", select: "-_id username", }) .populate({ path: "post_comments", model: "Comment", select: "-_id -__v comment_description comment_timestamp", // <-- 这里不生效 populate: { path: "comment_author", model: "User", select: "-_id:0 username" } })
针对post_comments的populate配置里的select语句完全不起作用,试了多种写法都无效,求问题原因和解决方案。
问题原因及解决方案
原因
你的postSchema里,post_comments是直接嵌入commentSchema.schema的数组,而非引用Comment模型的ObjectId数组。Mongoose的populate方法仅对**引用类型(ObjectId + ref关联)**字段生效,对于直接嵌入的子文档,populate配置会被忽略,所以select规则完全不生效。
解决方案
有两种可行方案:
方案1:修改Schema,将post_comments改为引用类型(推荐)
把postSchema中的post_comments改为关联Comment模型的ObjectId数组,这样populate就能正常工作:
postSchema = mongoose.Schema({ post_title, post_description, post_timestamp, post_author:{ type:mongoose.Schema.Types.ObjectId, ref: "User" }, post_likes:{ type: [userSchema.schema] }, post_comments:{ type: [mongoose.Schema.Types.ObjectId], // 改为ObjectId数组 ref: "Comment" // 关联Comment模型 } })
修改后,修正内层populate的select写法(-_id:0是错误语法,应写成-_id username),原查询代码即可生效:
const posts = await Post.find({}, { post_title: 1, post_description: 1, post_timestamp: 1 }) .populate({ path: "post_author", model: "User", select: "-_id username", }) .populate({ path: "post_comments", model: "Comment", select: "-_id -__v comment_description comment_timestamp", populate: { path: "comment_author", model: "User", select: "-_id username" // 修正语法 } })
方案2:查询时直接投影子文档字段(适合不想修改Schema的场景)
如果不想改动Schema结构,可在Post.find()的投影参数中指定post_comments要保留/移除的字段:
const posts = await Post.find({}, { post_title: 1, post_description: 1, post_timestamp: 1, post_author: 1, "post_comments.comment_description": 1, "post_comments.comment_timestamp": 1, "post_comments.comment_author": 1, "post_comments._id": 0, // 移除子文档的_id "post_comments.__v": 0 // 移除子文档的__v }) .populate({ path: "post_author", model: "User", select: "-_id username", }) .populate({ path: "post_comments.comment_author", model: "User", select: "-_id username" })
这种方法无需修改Schema,但投影写法较繁琐,子文档字段较多时维护成本高。
内容的提问来源于stack exchange,提问作者5.9 protons
相关产品推荐
相关产品推荐

