Home > Net >  MongoDB positional operators index issue using python and pymongo
MongoDB positional operators index issue using python and pymongo

Time:11-21

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"}]
})

Playground

  • Related