本文演示如何使用 $set 结合位置操作符 $ 替换 Array 中匹配条件的特定元素值。
创建示例数据
> db.replaceValueInArrayDemo.insertOne({"StudentScores":[45,56,78]});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd7f0421a844af18acdffb7") }
> db.replaceValueInArrayDemo.insertOne({"StudentScores":[33,90,67]});
{ "acknowledged" : true, "insertedId" : ObjectId("5cd7f0521a844af18acdffb8") }
显示原始数据
> db.replaceValueInArrayDemo.find().pretty();
{ "_id" : ObjectId("5cd7f0421a844af18acdffb7"), "StudentScores" : [ 45, 56, 78 ] }
{ "_id" : ObjectId("5cd7f0521a844af18acdffb8"), "StudentScores" : [ 33, 90, 67 ] }
替换第一个文档中值为 45 的元素为 99
> db.replaceValueInArrayDemo.update(
{ _id: ObjectId("5cd7f0421a844af18acdffb7"), StudentScores: 45 },
{ $set: { 'StudentScores.$': 99 } }
);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
验证结果
> db.replaceValueInArrayDemo.find().pretty();
{ "_id" : ObjectId("5cd7f0421a844af18acdffb7"), "StudentScores" : [ 99, 56, 78 ] }
{ "_id" : ObjectId("5cd7f0521a844af18acdffb8"), "StudentScores" : [ 33, 90, 67 ] }
核心机制解析
- Query 部分:
{ _id: ..., StudentScores: 45 }- 同时匹配文档 _id 和 Array 中包含值 45 - 位置操作符 $:
StudentScores.$- 定位到 Query 中匹配的 第一个 Array 元素位置 - $set: 将该位置的值设为 99
关键限制
- 只更新 第一个匹配 的 Array 元素
- Query 必须包含 Array Field 的精确值匹配(或 $elemMatch)
- 不支持更新多个匹配元素(需用 Aggregation $map 或应用层循环)
现代替代方案 (MongoDB 3.6+): arrayFilters
// 更新所有值为 45 的元素
db.replaceValueInArrayDemo.updateMany(
{ _id: ObjectId("5cd7f0421a844af18acdffb7") },
{ $set: { "StudentScores.$[elem]": 99 } },
{ arrayFilters: [{ elem: 45 }] }
);
Array of Objects 场景
// 将 items 中 productId="P001" 的 price 改为 29.99
db.orders.updateOne(
{ "items.productId": "P001" },
{ $set: { "items.$.price": 29.99 } }
);
相关操作符对比
| 操作 | 操作符 | 说明 |
|---|---|---|
| 替换元素值 | $set + $ | 精确替换匹配位置 |
| 修改对象内字段 | $set + $ | {$set: {"items.$.qty": 5}} |
| 添加元素 | $push/$addToSet | 末尾添加 |
| 删除元素 | $pull/$pullAll | 按值/按数组删除 |
| 按位置删除 | $unset + $pull | 先置 null 再 pull null |