Home > database >  Partial update overwriting nested fields in MongoDB and FastAPI
Partial update overwriting nested fields in MongoDB and FastAPI

Time:10-30

I have this schema

{
  "_id": "5060ad4b-fb4a-4a34-b44a-32e97626dc0a",
  "isDeleted": false,
  "user": {
    "timestamp": "2022-10-29",
    "name": "john2",
    "surname": "doe2",
    "email": "[email protected]",
    "phone": " 012345678912",
    "age": 20,
    "gender": "male",
    "nationality": "smth",
    "universityMajor": "ENGINEERING",
    "preferences": {
      "doesMindHavingPets": true,
      "isSmoker" : null,
      "isMorning" : false
    },
    "password": "f61a20da9eaa68a9f06dbc1710b10ef0a67208b2059b1f576af6deac23c215f5"
  },
  (Other stuff)
  .
  .
  .
  .
}

What i want to do is receive a partial update request from the client side that could look like this:

{
    "email" : "[email protected]",
    "password" : "asdfghj",
    "preferences" : {
        "isSmoker" : true,
        "doesMindHavingPets" : false
    }
}

So we could have the nested field preferences or not.

What I want is to merge the documents, I.e updating the email, password, and the preferences. The "outer" fields update just fine, the problem is that the fields in preferences get overwritten

For example:

Using the past request, the document would look like this:

{
  "_id": "5060ad4b-fb4a-4a34-b44a-32e97626dc0a",
  "isDeleted": false,
  "user": {
    "timestamp": "2022-10-29",
    "name": "john2",
    "surname": "doe2",
    "email": "[email protected]",
    "phone": " 012345678912",
    "age": 20,
    "gender": "male",
    "nationality": "smth",
    "universityMajor": "ENGINEERING",
    "preferences": {
      "doesMindHavingPets": false,
      "isSmoker" : true,
      "isMorning" : null
    },
    "password": "f61a20da9eaa68a9f06dbc1710b10ef0a67208b2059b1f576af6deac23c215f5"
  }
}

So the isMorning field got overwritten. The output I want is this:

{
  "_id": "5060ad4b-fb4a-4a34-b44a-32e97626dc0a",
  "isDeleted": false,
  "user": {
    "timestamp": "2022-10-29",
    "name": "john2",
    "surname": "doe2",
    "email": "[email protected]",
    "phone": " 012345678912",
    "age": 20,
    "gender": "male",
    "nationality": "smth",
    "universityMajor": "ENGINEERING",
    "preferences": {
      "doesMindHavingPets": false,
      "isSmoker" : true,
      "isMorning" : false
    },
    "password": "f61a20da9eaa68a9f06dbc1710b10ef0a67208b2059b1f576af6deac23c215f5"
  }
}

My current query that updates the "outer" fields is this:

update_result = await dbConnection.find_one_and_update({"_id": id}, 
        [ { "$set": { "user": { "$mergeObjects": [ "$user", new_user ] } }  } ], 
        return_document = ReturnDocument.AFTER))

new_user here is a dictionary of the received inputs, for the above JSON request, new_user looks like this:

{'email': '[email protected]', 'password': 'asdfghj', 'preferences': {'isSmoker': True, 'doesMindHavingPets': False}}

P.S: I am using FastAPI

I would appreciate any help :))

CodePudding user response:

One simple option is to divide it to nested and not nested stages:

db.collection.find_one_and_update(
  {_id: id},
  [
    {$set: {
      "user.preferences": {$mergeObjects: ["$user.preferences", new_user.preferences]}
    }},
    {$set: {
      user: {$mergeObjects: ["$user", new_user_first_layer]}
    }}
  ])

See how it works on the playground example

  • Related