0

I have a nested array that I would like to add to, but I'm having difficulty. My goal is to append to this array if it does not exist, and if it does, it will change the information within it.

For example, I'd like to edit the content of a dictionary within 'arr4' with the identification ('id4') of 'foo' from '...' to '!!!'.

This is setup with PyMongo here:

diction = {
  "arr1": [
    {
      "id1": "abc",
      "someInfo1": "...",
      "someInfo2": "...",
      "someInfo3": "...",
      "someInfo4": "...",
      "arr2": [
        {
          "id2": "ijk",
          "arr3": [
            {
              "id3": "xyz",
              "someInfo1": "...",
              "someInfo2": "...",
              "arr4": [
                {
                "id4": "foo",
                "someInfo": "..."
                },
                {
                "id4": "bar",
                "someInfo": "..."
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

import pymongo
from pymongo import MongoClient

client = MongoClient()
db = client['pymongo_test2']
db.posts.insert_one(diction)

In order to access these arrays, I think I would use array filters, so I tried

id1 = 'abc'
id2 = 'ijk'
id3 = 'xyz'
id4 = 'foo'

db.posts.update_one({}, {'$set': {'arr1.$[element1].arr2.$[element2].arr3.$[elemenet3].arr4': {'id4': 'foo', 'someInfo': '!!!'}, 'arrayFilters': {'element1.id1': id1, 'element2.id2': id2, 'elemenet3.id3': id3}}}, True)

but I get the error:

pymongo.errors.WriteError: No array filter found for identifier 'element1' in path 'arr1.$[element1].arr2.$[element2].arr3.$[elemenet3]'

Any help is greatly appreciated!

Seth
  • 51
  • 1
  • 7
  • The error comes because the MongoDB "server" instance you are connecting to does not support filtered positional `$[]` updates or `arrayFilters` options. You need at least MongoDB 3.6 in order to use the operators, just like the documentation and linked answer says. What is also in the linked answer are alternate approaches that apply to all versions. Primarily that mostly you should not be nesting arrays at all, as even with the new operators it's still not a great idea to do so. – Neil Lunn May 12 '18 at 21:50
  • @NeilLunn How would I go about enabling the filtered position or arrayFilters option because I do have MongoDB 3.6. – Seth May 13 '18 at 01:05
  • It does not look like you do. Check `db.version()` from within the `mongo` shell. Also check your `pymongo` driver version you have installed, as there *may* be issues with older drivers removing options. I actually cover these specifically on the linked question, but if you believe you still have something different then check the actual versions in both cases. – Neil Lunn May 13 '18 at 01:08
  • @NeilLunn It says "db version v3.6.4" for mongoDB, and it looks like pymongo is 3.6.1. – Seth May 13 '18 at 01:57
  • Okay then. I just checked anyway and your syntax is wrong. You have `arrayFilters` "inside" the update and not `array_filters` the "option". Also needs to be a "list" as per my answer on the linked duplicate. – Neil Lunn May 13 '18 at 02:02
  • 1
    `db.posts.update_one({}, { '$set': { "arr1.$[el1].arr2.$[el2].arr3.$[el3].arr4.$[el4].someInfo": "here" } }, array_filters=[{'el1.id1': 'abc'},{'el2.id2': 'ijk'},{'el3.id3':'xyz'},{'el4.id4':'foo'}])` - is the corrected statement – Neil Lunn May 13 '18 at 02:02
  • @NeilLunn Thank you very much for your help. One more question: I'd like for it to append to the array if the id does not exist. I thought upsert = True would do that, but it doesn't seem to be working. Instead, it looks like it does nothing instead of appending. – Seth May 13 '18 at 03:07
  • That's a different question completely, for which you can [Ask a new Question](https://stackoverflow.com/questions/ask). Being that you are currently just "playing", then I strongly urge that you rather consider the wisdom of the existing answer and "do not" construct embedded arrays like this. Even with the new operators for update, such a structure is completely impractical for query. That is the "real" underlying answer of the original content anyway. You really want a much "flatter" structure than you think you want for a practical database application. – Neil Lunn May 13 '18 at 04:15

0 Answers0