Rust中如何将MongoDB Decimal128转换为JSON字符串?
解决MongoDB Decimal128转JSON的格式问题
你在MongoDB中存储的数据格式如下:
[{"versions": {"version1": {"app": Decimal128(1.1)}}}]
用Rust转换为JSON字符串时,输出变成了:
[{"versions": {"version1": {"app": {"$numberDecimalBytes": [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 48]}}}}]
尝试用Decimal128.to_string()方法只能得到"Decimal128(...)"格式的输出,无法拿到实际的数值字符串或浮点数。
原因分析
直接返回Document时,serde对Decimal128的默认序列化会输出其内部字节数组结构;而Decimal128的to_string()是Debug实现,并非返回数值的字符串表示。
解决方案
方案一:手动遍历转换Document中的Decimal128
写一个辅助函数递归遍历Bson值,将遇到的Decimal128转换为字符串或浮点数,再转成可正常序列化的JSON结构。
示例代码:
use mongodb::bson::{Bson, Document, Decimal128}; use serde_json::Value as JsonValue; // 转换Bson为可正确序列化的JsonValue fn bson_to_json_value(bson: Bson) -> JsonValue { match bson { Bson::Document(doc) => { let mut json_obj = serde_json::Map::new(); for (key, value) in doc { json_obj.insert(key, bson_to_json_value(value)); } JsonValue::Object(json_obj) } Bson::Decimal128(d) => { // 转成字符串格式(保留完整精度) JsonValue::String(d.to_string().replace("Decimal128(", "").replace(")", "")) // 若要转浮点数,注意存在精度损失风险 // JsonValue::Number(serde_json::Number::from_f64(d.to_f64().unwrap_or(0.0)).unwrap()) } Bson::Array(arr) => { JsonValue::Array(arr.into_iter().map(bson_to_json_value).collect()) } other => serde_json::to_value(other).unwrap(), } } // 修改get_all_versions函数 pub fn get_all_versions(db_name: String) -> Result<Json<Vec<JsonValue>>, Status> { let db = MongoCLient::init(db_name); let versions = db.get_all_version()?; let json_versions: Vec<JsonValue> = versions .into_iter() .map(|doc| bson_to_json_value(Bson::Document(doc))) .collect(); Ok(Json(json_versions)) }
方案二:使用自定义结构体与serde自定义序列化
定义对应数据结构的结构体,为Decimal128实现自定义序列化逻辑,让serde直接按需求转换格式,无需手动遍历。
示例代码:
use mongodb::bson::Decimal128; use serde::{Serialize, Deserialize}; // 定义对应MongoDB数据的结构体(用于反序列化) #[derive(Debug, Deserialize)] struct VersionData { #[serde(rename = "versions")] versions: std::collections::HashMap<String, AppVersion>, } #[derive(Debug, Deserialize)] struct AppVersion { app: Decimal128, } // 定义用于序列化输出的结构体 #[derive(Debug, Serialize)] struct SerializedAppVersion { app: String, // 若用浮点数替换字符串:app: f64, } impl From<AppVersion> for SerializedAppVersion { fn from(av: AppVersion) -> Self { // 转字符串保留精度 let app_str = av.app.to_string().replace("Decimal128(", "").replace(")", ""); SerializedAppVersion { app: app_str } // 转浮点数的写法 // let app_f64 = av.app.to_f64().unwrap_or(0.0); // SerializedAppVersion { app: app_f64 } } } #[derive(Debug, Serialize)] struct SerializedVersionData { versions: std::collections::HashMap<String, SerializedAppVersion>, } impl From<VersionData> for SerializedVersionData { fn from(vd: VersionData) -> Self { let versions = vd.versions.into_iter() .map(|(k, v)| (k, v.into())) .collect(); SerializedVersionData { versions } } } // 修改查询和返回函数 pub fn get_all_version(&self) -> Result<Vec<VersionData>, Error> { let cursors = self .version_model .find(None, None) .ok() .expect("Error getting list of versions"); let versions = cursors.map(|doc| { let doc = doc.unwrap(); bson::from_document(doc).unwrap() }).collect(); Ok(versions) } pub fn get_all_versions(db_name: String) -> Result<Json<Vec<SerializedVersionData>>, Status> { let db = MongoCLient::init(db_name); let versions = db.get_all_version()?; let serialized_versions: Vec<SerializedVersionData> = versions.into_iter().map(|v| v.into()).collect(); Ok(Json(serialized_versions)) }
注意事项
- 转换为浮点数时可能存在精度损失,
Decimal128是高精度类型,建议优先使用字符串格式保留完整数值信息。 - 代码中的
unwrap()可根据业务需求替换为更严谨的错误处理逻辑,避免程序panic。
内容的提问来源于stack exchange,提问作者wenyi
相关产品推荐
相关产品推荐

