0

I have a MongoDB database with the following structure (simplified for the question's sake):

User:

"id": int
"aquarium": Aquarium[]

Aquarium:

"name": str
"fish": Fish[]

I have access to:

  • The database, which contains a list of objects of type User, which in turn have their own Aquarium objects (users_db)
  • The unique ID of the target User, which is supposed to be the subject of the operation (id)
  • The unique name of the Aquarium, which is supposed to be the subject of the operation (aquarium_name)
  • A Fish type object (obj)

My purpose is to push the Fish type object (refered to as "obj" in the code) into the target Aquarium's fish array.

So far I have attempted to achieve this with the following code:

    users_db.find_one_and_update
    (
        {
            "_id": ObjectId(str(id)),
            "aquarium.name": aquarium_name
        }, 
        {
            "$push": {"aquarium.fish": obj}
        }
    )

This was, however, unsuccessful. The following error was returned: The error displayed when the POST operation is performed

I have reviewed numerous other question, such as this one, however I could not find a question which simultaneously demands a query dependent on both the inner and outer layer and insertion into the inner layer at the same time. It is hard for me to tell whether the issue comes from an invalid query or an invalid update operation, therefore I am unsure of which direction to go from this point.

Does anybody know what could be the cause of this? I'd appreciate any help.

Panzer
  • 47
  • 7

2 Answers2

1

You get the mentioned problem as you are trying to add an object into the fish array which is a nested array (aquarium is also an array).

You need $ operator after aquarium. Aims to update the first matched aquarium array.

MongoDB query

db.collection.update({
  "_id": ObjectId("5a934e000102030405000000"),
  "aquarium.name": "Aqua A"
},
{
  "$push": {
    "aquarium.$.fish": {
      name: "Tortoise",
      color: "Green"
    }
  }
})

Demo @ Mongo Playground

users_db.find_one_and_update
    (
        {
            "_id": ObjectId(str(id)),
            "aquarium.name": aquarium_name
        }, 
        {
            "$push": {"aquarium.$.fish": obj}
        }
    )
Yong Shun
  • 35,286
  • 4
  • 24
  • 46
  • What is the purpose of the first code block? Replacing my existing code with the one from the second block seems to have fixed my bug and yelds a 200 code message, however it doesn't appear that new fish are actually being added. – Panzer Nov 29 '22 at 19:29
  • The first code block is the MongoDB query command for illustration purpose. For the `aquarium` object, the field `name` should be `aquarium_name` instead of `name`? [Demo](https://mongoplayground.net/p/n4plidyrmTS) – Yong Shun Nov 30 '22 at 01:15
  • The aquarium_name / name was actually a mixup on my end - aquarium is the field's name, aquarium_name is the name given to the query. I'll fix it in the OP. I'm executing your code on this aquarium: `[ {"fish": [], "name": "Akvar" } ] `. Your code executes sucessfully and afterwards I print the result of an analogous users.db.find_one_and_update. The resulting aquarium is successfully listed at that point (or "None" if an invalid aquarium_name is passed), except its 'fish' argument is still listed as just []. The same results are yielded from a GET HTTP method. Why could that be? – Panzer Nov 30 '22 at 01:47
0

While Yong's answer was very helpful and got me closer to the answer, ultimately it didn't entirely solve my problem.

What did, however, solve my issue, was using array_filters to find the appropriate entry.

The functional code is as below:

users_db.find_one_and_update(
  {"_id": ObjectID(str(id))},
  {"$push": {"aquarium.$[a].fish": obj}},
  array_filters=[{"a.name": aquarium_name}],
)
Panzer
  • 47
  • 7