Here my document for example:
[{
_id: ObjectId("609391f436e519039a634311"),
name: "Class A",
numOfStudents: 10,
students: [{
name: "Student A",
age: 10,
}, {
name: "Student B",
age: 10,
}]
}]
I want to update some values of class and remove some informations of all students in class. So I am using $set and $unset in updateOne, like below:
db.class.updateOne({
_id: ObjectId("609391f436e519039a634311")
}, {
$set: { something: "Something for describe" },
$unset: { "students.$[].age": "" }
})
But now, I want $set a value to something by value of another field, I have to convert above script to a pipeline like below:
db.class.updateOne({
_id: ObjectId("609391f436e519039a634311")
}, [
{
$set: { something: "$name" },
}, {
$unset: [
"students.$[].age"
]
}
])
But it didn't work, it threw an Error:
Invalid $unset :: caused by :: FieldPath field names may not start with '$'. Consider using $getField or $setField.
Please give me a suggestion for this.
CodePudding user response:
You can't use paths that we use in update operators in aggregation. When aggregate you can only use aggregate operators, ONLY exception is the match stage that you can use query operators also.
Query1
- unset age
update(
{"_id": ObjectId("609391f436e519039a634311")},
[{"$set": {"something": "$name"}},
{"$unset": ["students.age"]}])
Query2
- you can use the
"$$REMOVE"
system variable, if a field gets this value its removed - here is like setting all age fields to have value
$$REMOVE
so they are removed
update(
{"_id": ObjectId("609391f436e519039a634311")},
[{"$set": {"something": "$name", "students.age": "$$REMOVE"}}])
Query3
- from students we only keep the
name
(=>age
is removed) - you have to write by hand all the fields you want to keep
update(
{"_id": ObjectId("609391f436e519039a634311")},
[{"$set": {"something": "$name",
"students":
{"$map": {"input": "$students", "in": {"name": "$$this.name"}}}}}])