Your first and second updateOne queries are identical. I think the first one isn’t supposed to use the aggregation syntax and was actually meant to be:
const { insertedId } = await col.insertOne({
array: [{ name: "Obj1" }, { name: "Obj2" }, { name: "Obj3" }],
});
await col.updateOne(
{
_id: insertedId,
},
{
$set: { "array.1.name": "Update second array element only" },
},
);
Fully agreed. But I don’t know if the issue is with $set specifically or aggregations in general.
To fully appreciate the complicated-ness of it, if you were inserting at the 5th position of a longer array, you would need $concat: [slice-before, $merge: [updated-elem], slice-after]:
[
{
$set: {
array: {
$concatArrays: [
{ $slice: ["$array", 0, 5] },
[
{
$mergeObjects: [
{ $arrayElemAt: ["$array", 5] },
{ name: "Update fifth entry only" },
],
},
],
{ $slice: ["$array", 6, { $size: "$array" }] },
],
},
},
},
]
There are several operators that have different behaviours in aggregations vs updates, or just aren’t available. Like $push as an array operator just not being available in aggregations (in updates agg pipelines and agg queries). For aggregations, it’s only available in $bucket, $bucketAuto, $group, $setWindowFields.
Same goes for Array $addToSet vs Agg $addToSet.
Well, same goes for all Array update operators. Either not available in aggregations or have a completely different behaviour.
This is a good workaround but is only applicable for cases where “I want to update a single element in an array”. It doesn’t work for situations where you have a multi-stage aggregation pipeline where moving out one update op is impractical (and possibly incorrect).