Rust对接MongoDB时bson DateTime转标准JSON日期格式问题
解决方案
出现这个问题的原因是你当前用的bson::serde_helpers::chrono_datetime_as_bson_datetime序列化规则,会强制把chrono::DateTime序列化为BSON日期格式,不管当前序列化目标是BSON还是JSON,最终JSON序列化时就会生成带$date的嵌套结构。
下面是两种可落地的实现方案:
方案1:使用serde_with实现序列化规则自动适配
这种方案不需要修改业务逻辑,通过条件序列化规则自动适配MongoDB存储和JSON返回两个场景:
- 首先添加依赖到
Cargo.toml
[dependencies] serde_with = { version = "3.4", features = ["chrono"] } # 其余原有依赖保持不变
- 修改结构体定义
use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use serde_with::IfIsHumanReadable; use bson::serde_helpers::chrono_datetime_as_bson_datetime; #[serde_as] #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Management { // 其余属性保持不变 #[serde_as(as = IfIsHumanReadable<_, chrono_datetime_as_bson_datetime>)] pub created_at: DateTime<Utc>, }
规则说明:
- 当序列化目标为非可读格式(比如BSON,对应MongoDB存储场景),自动使用
chrono_datetime_as_bson_datetime规则,存为标准BSON日期类型 - 当序列化目标为可读格式(比如JSON,对应接口返回场景),自动使用chrono默认的序列化规则,输出ISO 8601格式的日期字符串
方案2:拆分数据库实体和接口响应DTO
这种方案不需要引入额外依赖,逻辑完全透明,适合对代码可控性要求高的场景:
- 定义数据库交互用的实体结构体,保持原有序列化规则不变:
#[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ManagementEntity { // 其余属性保持不变 #[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")] pub created_at: DateTime<Utc>, }
- 定义接口返回用的DTO结构体,并且实现实体到DTO的转换:
#[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct ManagementResp { // 其余属性和实体保持一致 pub created_at: String, } impl From<ManagementEntity> for ManagementResp { fn from(entity: ManagementEntity) -> Self { Self { // 其余属性直接透传 created_at: entity.created_at.to_rfc3339_opts(chrono::SecondsFormat::Secs, true) } } }
业务逻辑中从MongoDB查询得到ManagementEntity后,调用.into()即可转换为可直接序列化返回的ManagementResp。
内容的提问来源于stack exchange,提问作者Adrian Sanchez
相关产品推荐
相关产品推荐

