< 返回我的博客

wandercn 发表于 2024-03-12 16:21

Tags:mongodb,rust,json

自定义序列化函数

use bson::{oid::ObjectId, DateTime};
use chrono::{FixedOffset, Utc};
use mongodb::{bson::doc, options, Client, Collection};
use serde::{Deserialize, Serialize, Serializer};
use serde_json::to_string;
use std::str::FromStr;

// 时间戳转UTC时间字符串
pub fn datetime_to_utc<S>(value: &DateTime, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let formatted = value.to_string();
    serializer.serialize_str(&formatted)
}

// 时间戳转北京时间字符串
pub fn datetime_to_cst<S>(value: &DateTime, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let d: chrono::DateTime<Utc> = value.to_system_time().into();
    let east_8 = FixedOffset::east_opt(8 * 3600).unwrap();
    let formatted = d.with_timezone(&east_8).to_string();
    serializer.serialize_str(&formatted)
}

// ObjectId 转 hex 字符串
pub fn object_to_hex<S>(value: &ObjectId, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let formatted = value.to_hex();
    serializer.serialize_str(&formatted)
}

结构体定义

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Bacteria {
    #[serde(rename = "_id", serialize_with = "object_to_hex")]
    pub ID: ObjectId,
    pub hasGenome: bool,
    #[serde(serialize_with = "datetime_to_cst")]
    pub creationTime: DateTime,
}

解析打印的转json结果

{"_id":"5db131829181e500010b93d6",
"hasGenome":false,
"creationTime":"2019-10-24 13:07:14.109 +08:00"}

如果不启用自定义序列化器,结构体默认定义

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Bacteria {
    #[serde(rename = "_id")]
    pub ID: ObjectId,
    pub hasGenome: bool,
    pub creationTime: DateTime,
}

默认转换成json结果_id,creationTime的结果,跟MongoDB Compass 查询显示的不一致

{"_id":{"$oid":"5db131829181e500010b93d6"},
"hasGenome":false,
"creationTime":{"$date":{"$numberLong":"1571893634109"}}}

评论区

写评论
作者 wandercn 2024-03-12 17:54

如果字段中有map类型,map类型有包含DateTime 需要转换成北京cst时间。目前我只能这么实现

pub fn convert_to_cst(value: &DateTime) -> String {
    let d: chrono::DateTime<Utc> = value.to_system_time().into();
    let east_8 = FixedOffset::east_opt(8 * 3600).unwrap();
    d.with_timezone(&east_8).to_string()
}

pub fn serialize_location_map<S>(
    value: &HashMap<String, DateTime>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    // 创建一个新的序列化序列
    let mut map_serializer = serializer.serialize_map(Some(value.len()))?;

    // 遍历 HashMap 并序列化每个键值对
    for (key, value) in value {
        map_serializer.serialize_key(key)?;
        map_serializer.serialize_value(&convert_to_cst(value))?;
    }

    // 结束序列化序列
    map_serializer.end()
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Bacteria {
    // #[serde(rename = "_id")]
    #[serde(rename = "_id", serialize_with = "object_to_hex")]
    pub ID: ObjectId,
    pub hasGenome: bool,
    #[serde(serialize_with = "datetime_to_cst")]
    pub creationTime: DateTime,
    #[serde(serialize_with = "datetime_to_cst")]
    pub modifiedTime: DateTime,
    pub shortId: String,
    #[serde(serialize_with = "serialize_location_map")]
    pub location: HashMap<String, DateTime>,
    pub Taxonomy: bson::Document,
    pub backtrace: bson::Array,
}

转换成json结果如下,location字段Map结构的时间就能转换成北京时间的字符串:

{"_id":"5db131829181e500010b93d6",
"hasGenome":false,
"creationTime":"2019-10-24 13:07:14.109 +08:00",
"modifiedTime":"2023-07-27 14:26:26.944 +08:00","shortId":"B1D4D",
"location":{"R3T-A-5-3-K6":"2019-10-25 14:25:42.668 +08:00",
"R3R-A-9-2-L5":"2019-10-25 14:46:18.429 +08:00",
"R3R-A-10-3-L7":"2019-10-25 14:37:24.876 +08:00"},
"Taxonomy":{"class":"Unknown","phylum":"Unknown","kingdom":"Unknown","cnSpecies":"未知B1D4D","species":"Unknown","genus":"Unknown","family":"Unknown","order":"Unknown"},
"backtrace":["H2T73","H2RNV"]}
1 共 1 条评论, 1 页