Scala BSONDocument到JsObject并重写BSONDateTimeFormat
我将ReactiveMongo 0.11.11用于Play 2.5,并希望将BSONDocument转换为JsObject 对于大多数BSON数据类型(String、Int…),默认值完全可以让库完成这项工作。对于BSON类型的DateTime(Scala BSONDocument到JsObject并重写BSONDateTimeFormat,scala,reactivemongo,play-reactivemongo,Scala,Reactivemongo,Play Reactivemongo,我将ReactiveMongo 0.11.11用于Play 2.5,并希望将BSONDocument转换为JsObject 对于大多数BSON数据类型(String、Int…),默认值完全可以让库完成这项工作。对于BSON类型的DateTime(BSONDateTime),JSON属性的值没有提供我需要的格式 日期的JSON值是一个JsObject,其属性名为$Date,值为UNIX时间戳(以毫秒为单位): { "something": { "$date": 146228
BSONDateTime
),JSON属性的值没有提供我需要的格式
日期的JSON值是一个JsObject,其属性名为$Date
,值为UNIX时间戳(以毫秒为单位):
{
"something": {
"$date": 1462288846873
}
}
我想要的JSON是日期的字符串表示形式,如下所示:
{
"something": "2016-05-03T15:20:46.873Z"
}
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime =>
JsString(Instant.ofEpochMilli(dt.value).toString)
}
不幸的是,我不知道如何在不重写所有内容或更改库本身代码的情况下重写默认行为
这就是我认为它发生的地方():
我的版本必须如下所示:
{
"something": "2016-05-03T15:20:46.873Z"
}
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime =>
JsString(Instant.ofEpochMilli(dt.value).toString)
}
是否可以覆盖此位
我做了一个实验
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"}
}
}
我想指出的是,当我将BSONDocument转换为JsObject时,BSONDateTime到JsValue的转换应该始终有效,而不仅仅是当我手动选择特定的已知属性时。这意味着我的示例中的属性“something”可以有任何名称,也可以出现在子文档中
顺便说一句:如果你想知道的话,我通常在我的Play项目中使用BSON集合,但我不认为这在这种情况下有什么不同
编辑
我尝试过提供一个写入[BSONDateTime]
,但不幸的是,它没有被使用,我仍然得到与以前相同的结果。代码:
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}}
}
}
对于任何类型,BSON值都将使用转换为播放JSON 您需要在隐式范围中提供自己的
写入[BSONDateTime]
import reactivemongo.bson._
import play.api.libs.json._
object MyImplicits {
implicit val dateWrites = Writes[BSONDateTime] { date =>
???
}
def jsonDoc(doc: BSONDocument) =
JsObject(bson.elements.map(elem => elem._1 -> myJson(elem._2)))
implicit val docWrites = OWrites[BSONDocument](jsonDoc)
def myJson(value: BSONValue): JsValue = value match {
case BSONDateTime(value) = ???
case doc @ BSONDocument(_) => jsonDoc(doc)
case bson => BSONFormats.toJSON(bson)
}
}
/* where needed */ import MyImplicits.dateWrites
对于任何类型,BSON值都将使用转换为播放JSON 您需要在隐式范围中提供自己的
写入[BSONDateTime]
import reactivemongo.bson._
import play.api.libs.json._
object MyImplicits {
implicit val dateWrites = Writes[BSONDateTime] { date =>
???
}
def jsonDoc(doc: BSONDocument) =
JsObject(bson.elements.map(elem => elem._1 -> myJson(elem._2)))
implicit val docWrites = OWrites[BSONDocument](jsonDoc)
def myJson(value: BSONValue): JsValue = value match {
case BSONDateTime(value) = ???
case doc @ BSONDocument(_) => jsonDoc(doc)
case bson => BSONFormats.toJSON(bson)
}
}
/* where needed */ import MyImplicits.dateWrites
非常感谢您的回答!我已经实现了一个
编写[BSONDateTime]
,就像你建议的那样,但它似乎被忽略了。请参阅我问题中的编辑。我觉得这是因为我使用了BSONDocumentFormat
。你有什么想法吗?试试println(s“writer=${implicitly[Writes[BSONDateTime]]]}”)
Prints:writer=play.api.libs.json.Writes$$anon$6@b9c81b0
非常感谢您的回答!我已经实现了一个编写[BSONDateTime]
,就像你建议的那样,但它似乎被忽略了。请参阅我问题中的编辑。我觉得这是因为我使用了BSONDocumentFormat
。你有什么想法吗?试试println(s“writer=${implicitly[Writes[BSONDateTime]]]}”)
Prints:writer=play.api.libs.json.Writes$$anon$6@b9c81b0