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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:55:56