首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BSONDocument到JsObject并覆盖BSONDateTimeFormat

BSONDocument到JsObject并覆盖BSONDateTimeFormat
EN

Stack Overflow用户
提问于 2016-05-04 05:34:51
回答 1查看 1.1K关注 0票数 1

对于Play 2.5,我使用ReactiveMongo 0.11.11,并希望将BSONDocument转换为JsObject。

对于大多数BSON数据类型(String,Int.)默认设置完全可以让库完成这项工作。对于BSON类型DateTime (BSONDateTime),JSON属性的值不给我所需的格式。

日期的JSON值是一个JsObject,其属性名为$date,值以毫秒为单位,它的值为UNIX时间戳:

代码语言:javascript
复制
{
    "something": {
        "$date": 1462288846873
    }
}

我想要的JSON是日期的字符串表示形式,如下所示:

代码语言:javascript
复制
{
    "something": "2016-05-03T15:20:46.873Z"
}

不幸的是,我不知道如何在不重写库本身或更改代码的情况下重写默认行为。

这就是我认为它发生的地方(源代码):

代码语言:javascript
复制
val partialWrites: PartialFunction[BSONValue, JsValue] = {
    case dt: BSONDateTime => Json.obj("$date" -> dt.value)
}

我的版本应该是这样的:

代码语言:javascript
复制
val partialWrites: PartialFunction[BSONValue, JsValue] = {
    case dt: BSONDateTime =>
        JsString(Instant.ofEpochMilli(dt.value).toString)
}

有可能覆盖这一点吗?

我做了一个实验..。

代码语言:javascript
复制
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"}
    }

}

我想指出的是,当我将BSONDateTime转换为JsObject时,向BSONDocument的转换应该总是有效的,而不仅仅是当我手动选择一个特定的已知属性时。这意味着在我的示例中,属性“某某物”可以有任何名称,也可以出现在子文档中。

顺便说一句:如果你不知道,我通常会在我的游戏项目中使用BSON系列,但我不认为在这种情况下会有什么不同。

编辑

我尝试过提供一个Writes[BSONDateTime],但不幸的是它没有被使用,而且我仍然得到了和以前一样的结果。代码:

代码语言:javascript
复制
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}}
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-04 07:22:41

对于任何类型,BSON值都被转换为使用Writes[T]来播放JSON。

在这里,您需要在隐式范围内提供您自己的Writes[BSONDateTime]

代码语言:javascript
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37019274

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档