Mongoose嵌套Map字段异常:评论likes无法转为Map实例
Mongoose嵌套评论Map字段无法解析为Map实例问题
问题详情
定义postSchema和commentSchema分别对应帖子与嵌套评论,两者均用Map字段存储点赞数据。帖子的likes字段可正常调用set/get方法,但评论的likes调用时会报错,提示不是函数。具体现象:
- 创建评论时,
comment.likes是Map实例 - 更新帖子后查询结果,评论的
likes变为普通对象(显示为{}),instanceof Map返回false - 帖子点赞功能(
likePost)正常,评论点赞功能(likeComment)无法调用Map方法
相关代码
Post模型
import mongoose from 'mongoose'; const postSchema = mongoose.Schema( { userId: { type: String, required: true, }, userName: { type: String, required: true, }, picturePath: { type: String, default: '', }, title: { type: String, required: true, }, description: { type: String, required: true, }, likes: { type: Map, of: Boolean, default: new Map(), }, comments: { type: Array, default: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }], }, }, { timestamps: true } ); const Post = mongoose.model('Post', postSchema); export default Post;
Comment模型
import mongoose from 'mongoose'; const commentSchema = mongoose.Schema( { postId: { type: String, required: true, }, userId: { type: String, required: true, }, userName: { type: String, required: true, }, picturePath: { type: String, default: '', }, description: { type: String, required: true, }, likes: { type: Map, of: Boolean, default: new Map(), }, }, { timestamps: true } ); const Comment = mongoose.model('Comment', commentSchema); export default Comment;
添加评论接口
export const addComment = async (req, res) => { try { const { id } = req.params; const { userId, picturePath, description } = req.body; const user = await User.findById(userId); const newComment = new Comment({ id, userId, userName: user.userName, picturePath, //likes: {}, description, }); newComment.set('likes', new Map()); console.log(newComment.likes instanceof Map); const upDatedPost = await Post.findByIdAndUpdate( id, { $push: { comments: newComment } }, { new: true } ); const allPost = await Post.find(); console.log(allPost[0].comments[2].likes instanceof Map); res.status(200).json(allPost); } catch (err) { console.log('err'); res.status(404).json({ message: err.message }); } };
帖子点赞接口
export const likePost = async (req, res) => { try { const { id } = req.params; const { userId } = req.body; const post = await Post.findById(id); const isLiked = post.likes.get(userId); if (isLiked) { post.likes.delete(userId); } else { post.likes.set(userId, true); } const upDatedPost = await Post.findByIdAndUpdate( id, { likes: post.likes }, { new: true } ); res.status(200).json(upDatedPost); } catch (err) { res.status(404).json({ message: err.message }); } };
评论点赞接口
export const likeComment = async (req, res) => { try { const { id } = req.params; const { postId, userId } = req.body; let post = await Post.findById(postId); let comments = post.comments; console.log('comments: ', comments); console.log('likes: ', comments[0].likes); console.log( 'Is likes an instanceof Map: ', post.comments[0].likes instanceof Map ); //comments[0].likes.set(userId, true); //post.comments[0].set('likes', new Map()); //console.log(comments[6].likes); // comments.forEach((element) => { // if (element._id.toString() === id) { // element.likes.set(userId, true); // } // }); res.status(200).json(post); } catch (err) { res.status(404).json({ message: err.message }); } };
控制台输出
comments: [ { userId: '63dc0274bd8c03b1e417cfc4', userName: 'dummyUserThree', picturePath: '', description: 'Likes still not working', _id: new ObjectId("63e13f26603a052fc8f16b09"), likes: {} } ] likes: {} Is likes an instanceof Map: false
问题原因
postSchema中comments字段定义为普通数组,即便声明了ref: 'Comment',Mongoose也不会自动将数组内的对象转换为Comment文档实例,只会以普通JSON对象存储,导致其中的Map字段无法被解析为Map实例,仅保留为普通对象。
解决方法
方法1:使用子文档数组(推荐)
修改postSchema的comments字段,直接嵌入commentSchema作为子文档类型,让Mongoose自动处理嵌套文档的字段解析:
import mongoose from 'mongoose'; import commentSchema from './commentSchema.js'; // 导入评论Schema const postSchema = mongoose.Schema( { // 其他字段保持不变 comments: { type: [commentSchema], // 直接使用评论Schema作为数组元素类型 default: [] }, }, { timestamps: true } );
修改后,Mongoose会自动将数组内的每个评论的likes字段解析为Map实例,可直接调用set/get方法。
方法2:手动转换为Map
若要保留现有模式,查询帖子后需手动将评论的likes转换为Map实例:
export const likeComment = async (req, res) => { try { const { id } = req.params; const { postId, userId } = req.body; let post = await Post.findById(postId); // 手动转换每个评论的likes为Map post.comments.forEach(comment => { comment.likes = new Map(Object.entries(comment.likes)); }); // 找到目标评论并处理点赞 const targetComment = post.comments.find(c => c._id.toString() === id); if (targetComment) { const isLiked = targetComment.likes.get(userId); if (isLiked) { targetComment.likes.delete(userId); } else { targetComment.likes.set(userId, true); } await post.save(); // 保存更新后的帖子 } res.status(200).json(post); } catch (err) { res.status(404).json({ message: err.message }); } };
额外优化:添加评论逻辑调整
使用子文档模式后,无需单独创建Comment模型实例,直接创建符合Schema的对象即可:
export const addComment = async (req, res) => { try { const { id } = req.params; const { userId, picturePath, description } = req.body; const user = await User.findById(userId); // 直接创建子文档对象 const newComment = { userId, userName: user.userName, picturePath, description // likes会自动使用Schema中定义的默认值new Map() }; const updatedPost = await Post.findByIdAndUpdate( id, { $push: { comments: newComment } }, { new: true } ); res.status(200).json(updatedPost); } catch (err) { console.log('err'); res.status(404).json({ message: err.message }); } };
内容的提问来源于stack exchange,提问作者Zachary Freiter
相关产品推荐
相关产品推荐

