I am in the process of learning MongoDB and I have been attempting to update a nested array of songs, however, the positional operator seems to be updating the wrong index.
Here is the structure of the document in the database:
{
'_id': ObjectId(...),
'artistName': Artist Name,
'recordLabel': Label Name,
'genre': Genre,
'albums': [
{
'albumName': Album 1
'songs': [ Song 1, Song 2]
},
{
'albumName': Album 2
'songs': [ Song 3, Song 4]
},
]
}
Here is the update_one() function I am trying to execute:
artistcol.update_one(
{ 'albums.songs': 'Song 2' },
{ '$set': { 'albums.$[name].songs.$': 'Test 1' }},
array_filters=[{ 'name.albumName': 'Album 1' }]
)
The values in the execute function are being brought in from a form, but I just hardcoded the values for this post.
Expecting:
Based on the query above, I am looking for an object that has 'Song 2', and then using array filters to grab the right album object that its in and then a positional operator to grab the index of the song and change the value to 'Test 1'.
If I hardcode the album index, and song index by referencing the database it works but I need them to be dynamic because the user will select an album, song title, and then provide a new value for the song.
Actual:
When the query finishes, 'Song 1' has been updated to 'Test 1' and not 'Song 2'.
If I were to try:
artistcol.update_one(
{ 'albums.songs': 'Song 3' },
{ '$set': { 'albums.$[name].songs.$': 'Test 2' }},
array_filters=[{ 'name.albumName': 'Album 2' }]
)
It will update 'Song 4' to 'Test 2'.
What I'm understanding so far:
It appears that whatever index is found by the filter query, the positional operator ($) refers to that same index.
The only thing I need to figure out is how to target a specific array element within songs and change its value to whatever the user entered.
I have looked through a lot of documentation for MongoDB, tried to understand the best I could, and tried different things but I have not had any luck.
Any help would be appreciated, I do not know where to go from here. :)
CodePudding user response:
The positional operator will refer to the first element in the top-level array that matches the query.
In the query in the question, the $
refers to the matching album, i.e.
{
'albumName': Album 1
'songs': [ Song 1, Song 2]
},
Use the array filter to select the element of the nested array, like:
.update(
{"albums.songs": "Song 2"},
{$set: {"albums.$.songs.$[song]": "Tested"}},
{arrayFilters: [{song: "Song 2"}]
})