Rust操作MongoDB更新文档时未传嵌套字段被删除如何解决
问题根因
你当前的更新逻辑是用$set直接替换整个pet嵌套文档,新的pet对象中未包含can_live_with_other_cats、can_live_with_other_dogs两个字段,MongoDB会直接用新对象覆盖原有pet字段,导致原有字段被删除。
修复方案
不要替换整个pet对象,改用MongoDB的点表示法更新pet下的指定子字段,只会修改你传入的字段,其余原有字段会自动保留。修改后的代码示例如下:
async fn update(&self, adoption: &dto::adoption::update::Adoption) -> Result<(), Error> { let mongo_collection = MongoClient::get_collection("adoptions").await; let mongo_model = datamodel::insert_adoption::PetDataModel::from(&adoption.pet); let query = doc! {"_id": adoption.id.to_string()}; // 序列化后只包含非None的字段 let pet_fields = mongodb::bson::to_document(&mongo_model).unwrap(); // 构造带pet.前缀的更新路径 let mut update_content = Document::new(); for (field_name, field_value) in pet_fields { update_content.insert(format!("pet.{}", field_name), field_value); } // 如果需要更新pet以外的字段比如status,直接往update_content里加即可 // update_content.insert("status", "Adopted"); let update = doc! { "$set": update_content }; mongo_collection .update_one(query, update, None) .await .map(|_| ()) .map_err(|e| domain::errors::Error::internal_server_error(e.to_string())) }
注意事项
- 该方案复用了你现有结构体的
#[serde(skip_serializing_if = "Option::is_none")]逻辑,没有赋值的字段不会进入更新语句,完全符合部分更新的需求 - 相比先查旧文档合并字段再更新的方案,该方案只需要一次数据库请求,没有并发冲突问题,性能更高
内容的提问来源于stack exchange,提问作者Renato
相关产品推荐
相关产品推荐

