You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:17:48