MongoDB中db.find与db.aggregate输出差异及Node.js适配问题
Mongoose聚合查询结果数据丢失问题排查
问题场景
使用Node.js结合Mongoose操作MongoDB时,原通过Document.find查询指定字段(_id、name、size),后续因需要动态基于followers字段计算size,改用aggregate聚合查询(通过$match过滤、$project计算size)。两种查询返回结果表面都是对象类型,但在后续用map结合Promise.all处理时,find的结果能正常合并原有数据与新增的followerData,而aggregate的结果仅保留followerData,原有数据库数据丢失。
原find查询代码
Document.find( { userid: mongoose.Types.ObjectId(userId) }, { '_id':1, 'name':1, 'size':1, })
聚合查询代码
Document.aggregate([ {$match:{userid: mongoose.Types.ObjectId(userId), isDeleted: deleted }}, {$project:{ '_id':1, 'name':1, 'size': {$size: "$followers"} }} ])
数据处理代码
document = await Promise.all(document.map(async(doc) => { let followerData if (doc.size > 0) { const icon = await getIcon(doc.name) if (icon){ followerData = { socialIcon: icon, name: name, } } } return { ...doc._doc, followerData } }))
Schema定义
var socialSchema = new Schema({ userid: { type: mongoose.Schema.Types.ObjectId, ref: 'users', required: true, }, name: { type: String, max: 255 }, followers: [ { name: { type: String }, handle: { type: String }, }, ], size: { type: Number, default: function() { return this.followers.length }, } })
问题原因
- Mongoose的
find方法返回的是Mongoose Document实例,这类实例会将原始数据库数据存储在_doc属性中,因此使用...doc._doc可以正确展开出查询到的字段。 - 而
aggregate聚合查询返回的是普通JavaScript对象,并非Mongoose Document实例,这些对象本身不存在_doc属性。当你执行{ ...doc._doc, followerData }时,doc._doc为undefined,展开后就只剩下followerData,导致原有数据丢失。
解决方案
方案1:直接展开doc对象
修改数据处理代码中的返回语句,直接展开doc本身而非doc._doc:
return { ...doc, followerData }
方案2:让聚合查询返回Document实例(不推荐)
如果坚持需要Mongoose Document实例,可以在聚合方法后调用lean(false),但聚合结果用普通对象性能更优,一般不建议这么做:
Document.aggregate([/* 聚合管道配置 */]).lean(false)
额外注意
你的数据处理代码中存在一处潜在问题:followerData里的name: name应该改为name: doc.name,否则会引用未定义的全局变量或引发错误。
内容的提问来源于stack exchange,提问作者DevPy
相关产品推荐
相关产品推荐

