You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 10:36:05