我正在嘗試僅更新物件中的給定欄位。在這種情況下,物件是一個用戶,其架構如下所示:
class BasicUser(BaseModel):
timestamp: datetime = Field(default_factory=datetime.now)
name: str = Field(...)
surname: str = Field(...)
email: EmailStr = Field(...)
phone: constr(
strip_whitespace=True,
regex=r"^[\ ]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$",
)
age: PositiveInt = Field(...)
該用戶只是整個檔案的一部分。完整的檔案如下所示:

我正在使用 FastAPI,我只想從前端接收需要更新的欄位,我的端點如下所示:
@router.put('/user/{id}', response_description='Updates a user', response_model=DocumentWithoutPassword)
async def updateUser (id: str, user: BasicUserUpdate = Body(...)):
new_user = {k: v for k, v in user.dict().items() if v is not None}
new_user = jsonable_encoder(new_user)
if len(new_user) >= 1:
update_result = await dbConnection.update_one({"_id": id}, {"$set": { "user" : new_user}})
請求的正文可以包含任意數量的欄位(僅包括需要更新的欄位),例如正文可能如下所示:
{
"email" : "[email protected]"
}
或者
{
"email" : "[email protected]",
"phone" : " 123456789"
}
上述代碼的問題在于,當請求到達時,它不會更新欄位,而是僅使用電子郵件(如果電子郵件已發送)或電子郵件和電話(如果它們都已發送)覆寫整個用戶。
所以我的問題是如何在不覆寫所有內容的情況下更新用戶中的特定值
例如,我{"email" : "[email protected]"}作為正文發送,而不是更新電子郵件并將其他所有內容保持原樣。這是結果:

uj5u.com熱心網友回復:
假設生成的new_user物件確實只包含嵌套在user檔案中的欄位內的要更改的欄位(聽起來就是這種情況),那么這里最直接的選擇可能是使用聚合管道來描述更新。這種方法允許您訪問各種管道運算子,尤其是$mergeObjects運算子。更改以下行:
update_result = await dbConnection.update_one({"_id": id}, {"$set": { "user" : new_user}})
類似于:
update_result = await dbConnection.update_one({"_id": id}, [ { $set: { user: { $mergeObjects: [ "$user", new_user ] } } } ])
應該產生你想要的結果。在這個游樂場鏈接上查看它的演示。
一個普遍的問題確實浮現在腦海中。如果這些檔案代表用戶,那么將所有欄位嵌套在父欄位下是否有任何特殊價值user?它最終可能不會以一種或另一種方式產生很大的影響,但可以肯定的是,提出這個問題這一事實有助于證明嵌套資料可能會遇到一些小的額外摩擦(尤其是在不必要的情況下)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/517995.html
