MongoDB Document JSON转Scala样例类时日期转换异常解决方案
解决方案
别担心,这个问题在Scala操作MongoDB时太常见了!主要是MongoDB存储的日期格式(带$date的时间戳结构)和Scala默认的日期类型不兼容导致的,给你几个实用的解决办法:
1. 用Mongo驱动适配的日期类型定义样例类
MongoDB Scala驱动已经为常见的日期类型提供了自动转换支持,比如org.joda.time.DateTime或者Java 8的java.time.Instant。你可以直接把样例类的日期字段定义成这些类型:
import org.joda.time.DateTime import org.mongodb.scala.bson.ObjectId case class WorkOrder( _id: ObjectId, workOrderId: String, thingId: String, alertId: String, description: String, contactId: String, estimatedDuration: String, workOrderStatus: String, lifecycleStatus: String, maintenancePlanId: String, createdDate: DateTime, updatedDate: DateTime, lastViewedDate: DateTime, suggestedMaintenanceDate: DateTime, startDate: DateTime )
只要你的项目依赖里包含了对应的库(比如Joda Time或者Java 8时间库),驱动会自动处理$date格式到这些类型的转换,不用额外写代码。
2. 自定义编解码器适配你想用的日期类型
如果你的项目更倾向于用Java 8的LocalDateTime或者其他自定义日期类型,可以写一个专属的编解码器(Codec)来处理转换逻辑,然后注册到Mongo客户端:
比如针对java.time.Instant的编解码器示例:
import org.bson.{BsonReader, BsonWriter} import org.bson.codecs.{Codec, DecoderContext, EncoderContext} import java.time.Instant class InstantCodec extends Codec[Instant] { override def encode(writer: BsonWriter, value: Instant, encoderContext: EncoderContext): Unit = { writer.writeDateTime(value.toEpochMilli) } override def getEncoderClass: Class[Instant] = classOf[Instant] override def decode(reader: BsonReader, decoderContext: DecoderContext): Instant = { Instant.ofEpochMilli(reader.readDateTime()) } }
然后注册这个编解码器到Mongo客户端配置:
import org.mongodb.scala.MongoClientSettings import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries} import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY import org.mongodb.scala.bson.codecs.Macros._ // 注册编解码器 val codecRegistry = fromRegistries( fromProviders(classOf[WorkOrder]), // 样例类的自动编解码器 fromRegistries(new InstantCodec()), // 自定义的Instant编解码器 DEFAULT_CODEC_REGISTRY // 默认Mongo编解码器 ) // 配置客户端 val settings = MongoClientSettings.builder() .codecRegistry(codecRegistry) .build() val mongoClient = MongoClient(settings)
这样你的样例类里就可以放心用Instant类型来接收日期字段了。
3. 手动转换Document中的日期字段
如果只是临时处理或者不想改动全局配置,也可以在拿到Document后手动提取时间戳,转换成你需要的日期类型:
import java.time.Instant MongoFactory.WorkOrdercollection.find().subscribe( (doc: Document) => { // 手动提取日期时间戳并转换 val createdDate = Instant.ofEpochMilli(doc.getDateTime("createdDate").getValue) val updatedDate = Instant.ofEpochMilli(doc.getDateTime("updatedDate").getValue) // 其他日期字段同理 // 构建样例类实例 val workOrder = WorkOrder( _id = doc.getObjectId("_id"), workOrderId = doc.getString("workOrderId"), thingId = doc.getString("thingId"), alertId = doc.getString("alertId"), description = doc.getString("description"), contactId = doc.getString("contactId"), estimatedDuration = doc.getString("estimatedDuration"), workOrderStatus = doc.getString("workOrderStatus"), lifecycleStatus = doc.getString("lifecycleStatus"), maintenancePlanId = doc.getString("maintenancePlanId"), createdDate = createdDate, updatedDate = updatedDate, lastViewedDate = Instant.ofEpochMilli(doc.getDateTime("lastViewedDate").getValue), suggestedMaintenanceDate = Instant.ofEpochMilli(doc.getDateTime("suggestedMaintenanceDate").getValue), startDate = Instant.ofEpochMilli(doc.getDateTime("startDate").getValue) ) println(workOrder) }, (error: Throwable) => println(s"Query failed: ${error.getMessage}"), () => println("Done") )
这种方式虽然代码繁琐一点,但灵活性很高,适合小范围的场景。
内容的提问来源于stack exchange,提问作者Tejas R.
相关产品推荐
相关产品推荐

