使用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
相关产品推荐
相关产品推荐

