I have the following object in MongoDB.
{
_id: "9839021321",
forms: [
{
formName: "sample_form_name",
version: [
{
version: "1",
status: "Active"
}
]
}
]
}
And I want to update two of its properties. Add "Expiration Date" & update "Status".
{
_id: "9839021321",
forms: [
{
formName: "sample_form_name",
version: [
{
version: "1",
expirationDate: "2025-01-30",
status: "Inactive"
}
]
}
]
}
I would normally do the following:
db["flows"].updateMany(
{ "_id": { "$regex":"9839021321" } },
{
$set: {
"forms.$[f].version.$[v].expirationDate": "2025-06-26",
"forms.$[f].version.$[v].expirationDate": { $type: "date" },
"forms.$[f].version.$[v].status": "Inactive"
}
},
{
"arrayFilters": [
{ "f.formName": { "$eq": "sample_form_name" } },
{ "v.status": { "$eq": "Active" } }
]
});
Is there a way in which I can avoid having to copy paste the entire forms.$[f].version.$[v]
section for each parameter? Something like this (it doesn't work):
db["flows"].updateMany(
{ "_id": { "$regex":"9839021321" } },
{
"forms.$[f].version.$[v]": {
$set: {
"expirationDate": "2025-06-26",
"expirationDate": { $type: "date" },
"status": "Inactive"
}
}
},
{
"arrayFilters": [
{ "f.formName": { "$eq": "sample_form_name"} },
{ "v.status": { "$eq": "Active" } }
]
});
As well, can the same parameter be updated with multiple properties at once? Something like this:
db["flows"].updateMany(
{ "_id": { "$regex": "9839021321" } },
{ "forms.$[f].version.$[v]": {
$set: {
"expirationDate": ["2025-06-26", { $type: "date" }],
"status": "Inactive"
}
},
{
"arrayFilters": [
{ "f.formName": { "$eq": "sample_form_name" } },
{ "v.status": { "$eq": "Active" } }
]
});
Thanks.
Concern: If you are only update the document with id: 9839021321
, you should not use $regex
and updateMany
. Based on your current update query, you are updating document(s) for those _id
containing 9839021321
.
In your first update query, you can't have the same key name to update forms.$[f].version.$[v].expirationDate
for the value and type at the same time. Instead, why not just provide the Date
value.
In your second update query, the query is not executable due to the $set
operator position. Even fixing the syntax, unfortunetely the MongoDB update query doesn't support such "shortcut" and the result returned will be the version
object being overwritten as below:
"version": [
{
"expirationDate": [
"2025-06-26",
{
"$type": "date"
}
],
"status": "Inactive"
}
]
You will face the risk that the other field in the object(s) for version
array get overwritten/lost.
Approach 1: MongoDB update query
You have to specify each nested field and provide the Date value as below:
db.collection.update({
"_id": {
"$regex": "9839021321"
}
},
{
$set: {
"forms.$[f].version.$[v].expirationDate": new Date("2025-06-26"),
"forms.$[f].version.$[v].status": "Inactive"
}
},
{
"arrayFilters": [
{
"f.formName": {
"$eq": "sample_form_name"
}
},
{
"v.status": {
"$eq": "Active"
}
}
]
})
Demo Approach 1 @ Mongo Playground
Approach 2: MongoDB aggregation query to update
For aggregation query, it is allowed to update multiple fields in the object but you have to construct such long query for iterating both forms
objects and f.versions
conditionally.
db.flows.aggregate([
{
"$match": {
"_id": "9839021321"
}
},
{
"$set": {
"forms": {
"$map": {
"input": "$forms",
"as": "f",
"in": {
"$cond": {
"if": {
"$eq": [
"$$f.formName",
"sample_form_name"
]
},
"then": {
"$mergeObjects": [
"$$f",
{
"version": {
"$map": {
"input": "$$f.version",
"as": "v",
"in": {
"$cond": {
"if": {
"$eq": [
"$$f.formName",
"sample_form_name"
]
},
"then": {
"$mergeObjects": [
"$$v",
{
"expirationDate": new Date("2025-06-26"),
"status": "Inactive"
}
]
},
"else": "$$v"
}
}
}
}
}
]
},
"else": "$$f"
}
}
}
}
}
},
{
"$merge": {
"into": "9839021321",
"on": "_id",
"whenMatched": "replace"
}
}
])