MongoDB脚本报错:无法基于文档属性为数组新增属性
MongoDB数组元素更新报错解决方案
问题重现
执行以下更新脚本,意图为Invoices集合指定文档的Coupons数组元素新增PaymentMethods属性,值为包含对应PaymentMethod的数组:
db.Invoices.updateOne({_id: ObjectId("65edac6d5ac9a2cf10156800")}, [ { $set: { "Coupons.$.PaymentMethods": ["$Coupons.$.PaymentMethod"] } } ]);
触发错误:
Uncaught MongoServerError: Invalid $set :: caused by :: FieldPath field names may not start with '$'.
错误原因
在聚合管道模式的更新中,$set的值里直接写"$Coupons.$.PaymentMethod"会被MongoDB解析为FieldPath(字段路径),而非对字段值的引用。FieldPath不允许以$开头,因此触发报错。
解决方案(不使用游标或$map)
通过$filter定位匹配的数组元素,再提取其PaymentMethod值生成目标数组:
db.Invoices.updateOne( // 查询条件:匹配目标文档及存在PaymentMethod的Coupons元素 { _id: ObjectId("65edac6d5ac9a2cf10156800"), "Coupons.PaymentMethod": { $exists: true } }, [ { $set: { "Coupons.$.PaymentMethods": [ // 从Coupons数组中筛选出匹配的元素,提取其PaymentMethod值 { $getField: { field: "PaymentMethod", input: { $first: { $filter: { input: "$Coupons", cond: { $eq: ["$$this._id", "$Coupons.$._id"] } } } } } } ] } } ] );
说明
$filter用于从Coupons数组中筛选出与位置运算符$匹配的元素(通过_id匹配)$first获取筛选后的单个元素$getField提取该元素的PaymentMethod值,再包裹为数组赋值给PaymentMethods
如果需要更新Coupons数组中的所有元素,则无法避免使用$map(这是聚合管道中遍历数组的标准方式),对应的脚本如下:
db.Invoices.updateOne( { _id: ObjectId("65edac6d5ac9a2cf10156800") }, [ { $set: { "Coupons": { $map: { input: "$Coupons", as: "coupon", in: { $mergeObjects: [ "$$coupon", { PaymentMethods: ["$$coupon.PaymentMethod"] } ] } } } } } ] );
内容的提问来源于stack exchange,提问作者Wagner Meira Barbosa
相关产品推荐
相关产品推荐

