Hi @amenlust2 and welcome in the MongoDB Community! 
I have to say that this one made me sweat a little! 
First of all, you have a typo in your document above, it’s missing a '
after the field ftp
.
Then, I’m guessing that you need to provide some extra information to identify which element of the checks
array needs to be updated in the ports
array so I took the supposition / decision that number
was unique in your array of ports
and I assumed that this is how you identify which element to update as you probably don’t want to update all the checks
arrays.
So I simplified a bit the document model for the sake of the example:
db.c.drop()
db.c.insertOne({
"ip": "192.168.1.1",
"ports": [
{
"number": 21,
"checks": [
{
"name": "ABC",
"result": "success"
}
]
},
{
"number": 80,
"checks": []
},
{
"number": 444
}
]
})
Now that I have a sample document, let’s define some variables that I can use as query parameters.
const number = 21
const name = "DEF"
const description = "my new description"
const result = "my new result"
And here is the update query. This query loops through the ports array elements. When the provided number
is found, it removes the existing document with the provided name
from the checks
array (if it exists) and then appends the new document at the end.
db.c.updateOne({"ip": "192.168.1.1", "ports.number": number}, [{
"$set": {
"ports": {
"$map": {
input: "$ports",
as: "p",
in: {
"$cond": {
if: {"$eq": ["$$p.number", number]},
then: {
"$mergeObjects": ["$$p", {
"checks": {
"$concatArrays": [
{
"$filter": {
"input": "$$p.checks",
"cond": {"$ne": ["$$this.name", name]}
}
},
[{"name": name, "description": description, "result": result}]
]
}
}]
},
else: "$$p"
}
}
}
}
}
}]
)
Note that to support this query, you need the index:
db.c.createIndex({"ip": 1, "ports.number": 1})
Here is the result after the first execution of this query. As DEF
doesn’t exist in the checks
, it’s added in the array:
{
_id: ObjectId("64cbf22a5f5937b78f2b78b4"),
ip: '192.168.1.1',
ports: [
{
number: 21,
checks: [
{ name: 'ABC', result: 'success' },
{
name: 'DEF',
description: 'my new description',
result: 'my new result'
}
]
},
{ number: 80, checks: [] },
{ number: 444 }
]
}
Now if I provide new values for description
and result
but with the same name
and run the query again, this time the array entry is “updated”. (It’s actually removed and re-added in the query but you get the idea…).
const description = "my OTHER description"
const result = "my OTHER result"
Result:
{
_id: ObjectId("64cbf22a5f5937b78f2b78b4"),
ip: '192.168.1.1',
ports: [
{
number: 21,
checks: [
{ name: 'ABC', result: 'success' },
{
name: 'DEF',
description: 'my OTHER description',
result: 'my OTHER result'
}
]
},
{ number: 80, checks: [] },
{ number: 444 }
]
}
Enjoy!
Maxime 