如何用Mongoose实现数组元素内字段间的更新操作?
解决Mongoose中数组元素基于自身字段的增量更新问题
问题场景
给定如下Mongoose Holder模型:
import mongoose from 'mongoose' const holderSchema = new mongoose.Schema( { walletId: { type: String, required: true, unique: true, }, solBalance: { type: Number, default: 0, min: 0, }, liquidityPools: [ { collectionId: { type: mongoose.Schema.Types.ObjectId, required: true, }, lpTokens: { type: Number, required: true, min: 0, }, feeEarned: { type: Number, default: 0, min: 0, }, isActive: { type: Boolean, default: true, }, }, ], }, { timestamps: true } ) export default mongoose.models.Holder || mongoose.model('Holder', holderSchema)
需要实现:对所有文档中liquidityPools数组内collectionId等于指定值、且isActive为true的元素,执行feeEarned += lpTokens / 100的更新操作。
原尝试代码(无法生效):
await Holder.updateMany( { 'liquidityPools.collectionId': collectionId, 'liquidityPools.isActive': true }, { $inc: { 'liquidityPools.$[elem].feeEarned': { $multiply: [ 'elem.lpTokens', 100 ], }, }, } )
失效原因
$inc操作符仅支持传入数值常量,不能直接使用聚合表达式(如$multiply、$divide)基于文档自身字段计算增量。要实现这种依赖字段的更新,必须使用MongoDB 4.2及以上版本支持的聚合管道式更新。
正确实现方案
方案1:使用$map遍历数组(兼容MongoDB 4.2+)
通过$map遍历数组,对符合条件的元素执行计算更新:
await Holder.updateMany( // 仅匹配包含目标元素的文档,减少无效更新 { 'liquidityPools': { $elemMatch: { collectionId, isActive: true } } }, [ { $set: { liquidityPools: { $map: { input: '$liquidityPools', as: 'pool', in: { $cond: [ // 判断当前元素是否满足条件 { $and: [ { $eq: ['$$pool.collectionId', collectionId] }, { $eq: ['$$pool.isActive', true] } ]}, // 满足条件则更新feeEarned { ...'$$pool', feeEarned: { $add: ['$$pool.feeEarned', { $divide: ['$$pool.lpTokens', 100] }] } }, // 不满足则保留原元素 '$$pool' ] } } } } } ] )
方案2:结合数组过滤器的聚合更新(兼容MongoDB 5.0+)
MongoDB 5.0+支持在聚合管道中使用数组过滤器定位元素,写法更简洁高效:
await Holder.updateMany( { 'liquidityPools': { $elemMatch: { collectionId, isActive: true } } }, [ { $set: { 'liquidityPools.$[elem].feeEarned': { $add: [ '$liquidityPools.$[elem].feeEarned', { $divide: ['$liquidityPools.$[elem].lpTokens', 100] } ] } } } ], { arrayFilters: [{ 'elem.collectionId': collectionId, 'elem.isActive': true }] } )
该方案直接通过arrayFilters定位目标元素,无需遍历整个数组,性能更优。
内容的提问来源于stack exchange,提问作者Alwin Helor
相关产品推荐
相关产品推荐

