Joda DateTime
って最近はもうトレンドじゃない?
とにもかくにも、今現在進行形で使っていてMongoDBにISODate
として保存したい。
けど流石に公式サポートされてる型じゃないんでCan't find a codec for class org.joda.time.DateTime.
って怒られちゃいます。(下記コード)
わざわざ文字列にするのもあれだし、ということでスマートにコーデックを作る方法です。
import org.mongodb.scala._
import org.mongodb.scala.bson.codecs.Macros._
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
import org.bson.codecs.configuration.CodecRegistries.{fromRegistries, fromProviders}
import scala.concurrent.duration._
import org.joda.time.{DateTime, DateTimeZone}
import org.joda.time.format.DateTimeFormat
case class Post(title: String, body: String, createAt: DateTime)
val tz = DateTimeZone.forID("Asia/Tokyo")
val format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withZone(tz)
val codecRegistry = fromRegistries(fromProviders(classOf[Post]), DEFAULT_CODEC_REGISTRY)
val uri = "mongodb://root:password@localhost:27017/?authSource=admin"
val db = MongoClient(uri).getDatabase("example_db")
val posts: MongoCollection[Post] = db.withCodecRegistry(codecRegistry).getCollection("posts")
val post = Post("記事のタイトル", "本文だよ!", format.parseDateTime("2020-10-01 10:00:00"))
// 【ここでエラー!】 org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.joda.time.DateTime.
Await.result(posts.insertOne(post).toFuture, 1 second)
コーデック実装
ほいじゃま、コーデック作りましょう。
BsonWriter.writeDateTime
でミリ秒からISODate
に変換してくれます。
逆にBsonReader.readDateTime
はミリ秒を返してくれるので、DateTime
のコンストラクタにそのまま食わせればOK。
import org.bson.codecs.{Codec, DecoderContext, EncoderContext}
import org.bson.{BsonReader, BsonWriter}
import org.joda.time.DateTime
/**
* Joda DateTimeをBSONのISODateTime形式に相互変換するコーデック
*/
class JodaCodec extends Codec[DateTime] {
override def encode(writer: BsonWriter, value: DateTime, encoderContext: EncoderContext): Unit = writer.writeDateTime(value.getMillis)
override def decode(reader: BsonReader, decoderContext: DecoderContext): DateTime = new DateTime(reader.readDateTime)
override def getEncoderClass: Class[DateTime] = classOf[DateTime]
}
そしたら先のコードのコーデックを追加して完了!
import org.bson.codecs.configuration.CodecRegistries
// 中略
val codecRegistry = fromRegistries(
fromProviders(classOf[Post]),
DEFAULT_CODEC_REGISTRY,
CodecRegistries.fromCodecs(new JodaCodec)
)
結果
上記の結果で登録されたドキュメントはこんな感じ。ばっちりですね!
もちろんfind
も問題ないですよ!
{
"_id" : ObjectId("5f6d72a791a89d611a21174d"),
"title" : "記事のタイトル",
"body" : "本文だよ!",
"createAt" : ISODate("2020-10-01T01:00:00.000Z")
}
コメント