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

使用find_one获取ObjectId时格式不符合预期问题求助

MongoDB Rust Driver: BsonDeserialization Error When Fetching ObjectId

我最近在使用Rust的MongoDB驱动时碰到了一个反序列化问题,特意来请教大家。先看我的代码:

let users_coll = db.database("foo").collection::<bson::oid::ObjectId>("users");
let user_id = users_coll
    .find_one(
        doc! { "email": &account.email },
        mongodb::options::FindOneOptions::builder()
            .projection(doc! { "_id": 1i32 })
            .build(),
    )
    .await?
    .unwrap();

这段代码想根据邮箱查询用户的_id(ObjectId类型),但在?运算符的位置抛出了以下错误:

Error { kind: BsonDeserialization(DeserializationError { message: "expected map containing extended-JSON formatted ObjectId, instead found { \"_id\": ObjectId(\"62af199df4a16d3ea6056536\") }" }), labels: {}, wire_version: None, source: None }

错误提示说得很清楚:驱动期望的是扩展JSON格式的ObjectId(也就是{ "$oid": "..." }这种结构),但实际返回的是MongoDB内部的ObjectId("62af199df4a16d3ea6056536")格式,导致反序列化失败。我明白问题出在哪,但不知道具体该怎么修正,希望大家能帮忙指点一下!


解决方案

问题的核心是:你给collection指定了<bson::oid::ObjectId>泛型参数,这相当于告诉驱动——这个集合里的每一个文档都是单独的ObjectId值,但实际上你的users集合里的文档是包含_id字段的完整BSON文档,所以驱动尝试把整个文档反序列化成单个ObjectId时必然失败。

这里有两种简单的修正方式:

方式1:用结构体或Document接收结果再提取ObjectId

你可以定义一个只包含_id字段的结构体来接收查询结果,或者直接用bson::Document来获取,然后从中提取ObjectId:

// 用结构体接收的写法
use serde::Deserialize;
use bson::oid::ObjectId;

#[derive(Debug, Deserialize)]
struct UserId {
    #[serde(rename = "_id")]
    id: ObjectId,
}

let users_coll = db.database("foo").collection("users");
let user_id_doc = users_coll
    .find_one(
        doc! { "email": &account.email },
        mongodb::options::FindOneOptions::builder()
            .projection(doc! { "_id": 1 }) // 这里1i32可以简化成1,效果一致
            .build(),
    )
    .await?
    .unwrap();

let user_id: ObjectId = user_id_doc.id;

如果不想定义结构体,直接用Document提取更快捷:

let users_coll = db.database("foo").collection("users");
let user_id_doc = users_coll
    .find_one(
        doc! { "email": &account.email },
        mongodb::options::FindOneOptions::builder()
            .projection(doc! { "_id": 1 })
            .build(),
    )
    .await?
    .unwrap();

let user_id = user_id_doc.get_object_id("_id").unwrap();

方式2:链式调用直接映射提取

你也可以在获取find_one的结果后,直接链式调用提取ObjectId,省去中间变量:

let users_coll = db.database("foo").collection("users");
let user_id = users_coll
    .find_one(
        doc! { "email": &account.email },
        mongodb::options::FindOneOptions::builder()
            .projection(doc! { "_id": 1 })
            .build(),
    )
    .await?
    .unwrap()
    .get_object_id("_id")
    .unwrap();

两种方式都能解决问题,你可以根据自己的代码风格选择。


内容的提问来源于stack exchange,提问作者marknikky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:32:34