ReactiveMongo + Play Json неправильно хранит datetime в mongodb
Я пытаюсь сохранить
java.time.Instant
в собственном формате монго.
В официальной документации ReactiveMongo указано, что дата и время должны быть сериализованы как
JsObject with a $date JsNumber field with the timestamp (milliseconds) as value
( http://reactivemongo.org/releases/1.0/documentation/json/overview.html )
Я следую этому правилу, но значение не хранится как монго
Date
вместо этого он сохраняется как обычный документ JSON (BSON):
{
"_id" : ObjectId("6057b962af0000af00e81ec7"),
"username" : "john",
"createdAt" : {
"$date" : NumberLong(1616361826198)
}
}
Исходный код Scala, в котором хранится документ:
import play.api.libs.json.Json
import reactivemongo.api.DB
import reactivemongo.api.bson.BSONObjectID
import reactivemongo.api.bson.collection.BSONCollection
import java.time.Instant
import scala.concurrent.{ ExecutionContext, Future }
import reactivemongo.play.json.compat._
import json2bson._
import reactivemongo.api.commands.WriteResult
class Repo(database: DB)(implicit ec: ExecutionContext) {
def collection: BSONCollection =
database.collection("users")
def insertDocument(): Future[WriteResult] = {
val doc = Json.obj(
"_id" -> BSONObjectID.generate(),
"username" -> "john",
"createdAt" -> Json.obj("$date" -> Instant.now().toEpochMilli)
)
collection.insert.one(doc)
}
}
Что здесь не так?
PS:
Если я изменю расширенный синтаксис BSON
Json.obj("$date" -> Instant.now().toEpochMilli)
к
BSONDateTime
:
...
"createdAt" -> BSONDateTime(Instant.now().toEpochMilli)
...
оно работает.
Но все же, почему он не работает с расширенным синтаксисом play JSON +?
1 ответ
Расширенное представление MongoDB JSON не является действительным v2 на сегодняшний день . В
$date
значение должно быть либо форматированной строкой, либо длинным
{"$numberLong": "<millis>"}
scala> BSONValue.pretty(implicitly[BSONValue](Json.obj("$date" -> Instant.now().toEpochMilli)))
res12: String =
{
'$date': NumberLong(1616415630059)
}
scala> BSONValue.pretty(implicitly[BSONValue](Json.obj("$date" -> Instant.now().toString)))
res13: String = ISODate('2021-03-22T12:20:37.571Z')
scala> BSONValue.pretty(implicitly[BSONValue](Json.obj("$date" -> Json.obj("$numberLong" -> Instant.now().toEpochMilli.toString))))
res16: String = ISODate('2021-03-22T12:21:48.843Z')
При этом использование JSON для представления внутреннего запроса (без значения, поступающего как JSON из другого источника, например REST API) бесполезно и дорого.
При необходимости убедитесь, что у вас есть весь необходимый импорт (например,
extended._
один).