Ich verwende ReactiveMongo 0.11.11 für Play 2.5 und möchte ein BSONDocument in ein JsObject konvertieren.BSONDokument zu JsObject und überschreiben BSONDateTimeFormat
Für die meisten BSON-Datentypen (String, Int ...) sind die Standardwerte vollkommen in Ordnung, damit die Bibliothek die Aufgabe ausführen kann. Für BSON Typ DateTime (BSONDateTime
) gibt mir der Wert der JSON-Eigenschaft nicht das Format, das ich brauche.
Der JSON-Wert für ein Datum ist ein JSObject mit Eigenschaftsnamen $date
und ein UNIX-Zeitstempel in Millisekunden als Wert:
{
"something": {
"$date": 1462288846873
}
}
Die JSON ich so eine String-Darstellung des Datums ist will:
Leider weiß ich nicht, wie Sie das Standardverhalten überschreiben, ohne alles neu zu schreiben oder Code in der Bibliothek selbst zu ändern. Diese
ist, wo ich denke, es passiert (source code):
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime => Json.obj("$date" -> dt.value)
}
Meine Version würde wie folgt aussehen haben:
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime =>
JsString(Instant.ofEpochMilli(dt.value).toString)
}
Ist es möglich, dieses Bit außer Kraft zu setzen?
Ich habe ein Experiment erstellt ...
import java.time.Instant
import play.api.libs.json._
import reactivemongo.bson._
import reactivemongo.play.json.BSONFormats.BSONDocumentFormat
object Experiment {
// Original document (usually coming from the database)
val bson = BSONDocument(
"something" -> BSONDateTime(1462288846873L) // equals "2016-05-03T15:20:46.873Z"
)
// Reader: converts from BSONDateTime to JsString
implicit object BSONDateTimeToJsStringReader extends BSONReader[BSONDateTime, JsString] {
def read(bsonDate: BSONDateTime): JsString = {
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
}
}
// Reader: converts from BSONDateTime to JsValue
implicit object BSONDateTimeToJsValueReader extends BSONReader[BSONDateTime, JsValue] {
def read(bsonDate: BSONDateTime): JsValue = {
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
}
}
// Read and print specific property "something" using the `BSONReader`s above
def printJsDate = {
val jsStr: JsString = bson.getAs[JsString]("something").get
println(jsStr) // "2016-05-03T15:20:46.873Z"
val jsVal: JsValue = bson.getAs[JsValue]("something").get
println(jsVal) // "2016-05-03T15:20:46.873Z"
}
// Use ReactiveMongo's default format to convert a BSONDocument into a JsObject
def printAsJsonDefault = {
val json: JsObject = BSONDocumentFormat.writes(bson).as[JsObject]
println(json) // {"something":{"$date":1462288846873}}
// What I want: {"something":"2016-05-03T15:20:46.873Z"}
}
}
Ich mag würde zu beachten, dass die Umstellung auf BSONDateTime JsValue sollte immer funktionieren, wenn ich einen BSONDocument zu JSObject konvertieren, nicht nur, wenn ich manuell einem bestimmten Pick bekannte Eigenschaft. Das bedeutet, dass die Eigenschaft "etwas" in meinem Beispiel einen beliebigen Namen haben und auch in einem Unterdokument erscheinen kann.
BTW: Falls Sie sich fragen, ich arbeite normalerweise mit BSON-Sammlungen in meinem Play-Projekt, aber ich denke nicht, dass es in diesem Fall einen Unterschied macht.
bearbeiten
Ich habe versucht, eine Writes[BSONDateTime]
bietet, aber leider ist es nicht verwendet wird, und ich immer noch das gleiche Ergebnis wie zuvor. Code:
import java.time.Instant
import play.api.libs.json._
import reactivemongo.bson.{BSONDocument, BSONDateTime}
object MyImplicits {
implicit val dateWrites = Writes[BSONDateTime] (bsonDate =>
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
)
// I've tried this too:
// implicit val dateWrites = new Writes[BSONDateTime] {
// def writes(bsonDate: BSONDateTime) = JsString(Instant.ofEpochMilli(bsonDate.value).toString)
// }
}
object Experiment {
// Original document (usually coming from the database)
val bson = BSONDocument("something" -> BSONDateTime(1462288846873L))
// Use ReactiveMongo's default format to convert a BSONDocument into a JsObject
def printAsJson = {
import reactivemongo.play.json.BSONFormats.BSONDocumentFormat
import MyImplicits.dateWrites // import is ignored
val json: JsObject = BSONDocumentFormat.writes(bson).as[JsObject]
//val json: JsValue = Json.toJson(bson) // I've tried this too
println(json) // {"something":{"$date":1462288846873}}
}
}
Vielen Dank für Ihre Antwort! Ich habe ein 'Writes [BSONDateTime]' wie du vorgeschlagen implementiert, aber es scheint ignoriert zu werden. Siehe Bearbeiten in meiner Frage. Irgendwie habe ich das Gefühl, weil ich 'BSONDocumentFormat' verwende. Hast du eine Idee? – Nick
Probieren Sie 'println (s" writer = $ {implizit [Schreibt [BSONDateTime]]} ") – cchantep
Drucke:' writer = play.api.libs.json.Writes $$ anon $ 6 @ b9c81b0' – Nick