MongoDB 4.2.13:如何用聚合管道为数组首元素新增字段?
MongoDB 4.2.13 为数组第一个元素新增paid字段并赋值为自身price的正确方法
问题场景
使用MongoDB v4.2.13,Transaction集合的文档结构如下:
{ "id": 1, "product": [ { "name": "Book", "price": 100 }, { "name": "Pen", "price": 10 } ] }
需要为product数组的第一个元素新增paid字段,值等于该元素的price字段,预期结果:
{ "id": 1, "product": [ { "name": "Book", "price": 100, "paid": 100 }, { "name": "Pen", "price": 10 } ] }
之前使用聚合管道的$addFields尝试更新,结果不符合预期:
db.Transaction.updateOne( { id: 1 }, [ { $addFields: { "product.0.paid": { $arrayElemAt: ["$product.price", 0] } } } ] )
实际结果中所有product元素都被添加了0.paid嵌套字段,而非仅修改第一个元素。
错误原因
在聚合管道的$addFields/$set中,直接使用"product.0.paid"这种路径时,MongoDB会将其解析为给数组的每个元素添加嵌套字段,而非定位到索引为0的元素进行修改,这就导致了所有元素都被错误修改。
正确解决方案
方案一:使用$map结合$indexOfArray和$mergeObjects
通过遍历数组,判断元素索引是否为0,仅对第一个元素合并paid字段:
db.Transaction.updateOne( { id: 1 }, [ { $set: { product: { $map: { input: "$product", as: "item", in: { $cond: [ { $eq: [{ $indexOfArray: ["$product", "$$item"] }, 0] }, { $mergeObjects: ["$$item", { paid: "$$item.price" }] }, "$$item" ] } } } } } ] )
方案二:拆分数组后修改再合并
先拆分出第一个元素和剩余元素,修改第一个元素后重新合并数组,最后清理临时字段:
db.Transaction.updateOne( { id: 1 }, [ { $set: { firstProduct: { $arrayElemAt: ["$product", 0] }, restProducts: { $slice: ["$product", 1, { $size: "$product" }] } } }, { $set: { firstProduct: { $mergeObjects: ["$firstProduct", { paid: "$firstProduct.price" }] }, product: { $concatArrays: [["$firstProduct"], "$restProducts"] } } }, { $unset: ["firstProduct", "restProducts"] } ] )
两种方案都能实现预期效果,可根据实际场景选择。
内容的提问来源于stack exchange,提问作者Tan Nguyen
相关产品推荐
相关产品推荐

