Search code examples
arraysmongodbupdates

Update value in array of string on array of objects mongodb


I'm trying to update a value of a array of strings in mongodb, which is inside of another array of objects

here is an example of the model

{ 
    "_id" : ObjectId("5a8cd02f87d4839d279f6559"), 
    "category" : "0",
    "email" : "[email protected]",
    "password" : "doctor",
    "name" : "doctor",
    "directorys" : [ { 
                       "path" : "[email protected]/own/", 
                       "files" : [ "" ] 
                     }, 
                     {
                       "path" : "[email protected]/modified/",
                       "files" : [ "" ] 
                     },
                     { 
                      "path" : "[email protected]/own/pacient1", 
                      "files" : [ "", "README.txt" ] 
                     } 
                   ] }
}

So im trying to update the name "README.txt" to "README2.txt" but i'm struggling with mongo

i tried this

db.users.update({"email":"[email protected]","directorys.files":"README.txt"},{"$set":{"directorys.files.$":"README2.txt"}})

but throws the following error

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 16837,
        "errmsg" : "cannot use the part (directorys of directorys.files.2) to traverse the element ({directorys: [ { path: \"[email protected]/own/\", files: [ \"\" ] }, { path: \"[email protected]/modified/\", files: [ \"\" ] }, { path: \"[email protected]/own/pacient1\", files: [ \"\", \"README.txt\" ] } ]})"
    }
})

what i am missing? i dont know what to do


Solution

  • Since directorys is an array, I think you need an array operator there as well. Try this query:

    db.users.update(
        {"email":"[email protected]","directorys.files":"README.txt"},
        {"$set":{"directorys.$[selectedFiles].files.$":"README2.txt"}},
        {arrayFilters: [{"selectedFiles.files": "README.txt"}]}
    )
    

    You can see more about arrayFilters here: https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#up.S[]

    ArrayFilters allows you to take an array, select only those elements that match a certain criteria, and then apply $set (or any other update / upsert operator) to just those elements.

    One thing though is that this will only update the first element of your files array that has README.txt. If README.txt is present more than once, you won't update all of them. If you want to update all elements in the array that are README.txt, you need a second arrayFilter, like this:

    db.users.update(
        {"email":"[email protected]","directorys.files":"README.txt"},
        {"$set":{"directorys.$[selectedDirs].files.$[selectedFiles]":"README2.txt"}},
        {arrayFilters: [{"selectedDirs.files": "README.txt"}, {"selectedFiles": "README.txt"}]}
    )
    

    That should select all directorys elements with a files array that has at least one README.txt, then select all elements within that files array that equals README.txt, and then set those elements to README2.txt.