2016-05-04 2 views
0

私はReactiveMongo 0.11.11をPlay 2.5に使用し、BSONDocumentをJsObjectに変換したいと考えています。JsObjectへのBSONDocumentとBSONDateTimeFormatをオーバーライド

ほとんどのBSONデータ型(String、Int ...)の場合、デフォルトではライブラリがその作業を行うために完全に正常です。 BSON型DateTime(BSONDateTime)の場合、JSONプロパティの値は私に必要なフォーマットを与えません。私がしたいJSONは、このような日付の文字列表現である

{ 
    "something": { 
     "$date": 1462288846873 
    } 
} 

日のためのJSONの値は、プロパティ名$dateでのJSObjectとその値としてミリ秒単位のUNIXタイムスタンプである

{ 
    "something": "2016-05-03T15:20:46.873Z" 
} 

残念ながら、ライブラリ自体のすべてを書き換えたりコードを変更することなく、デフォルトの動作を上書きする方法はわかりません。私はそれが(source code)たまたまだと思うどこ

これは、次のとおりです。

val partialWrites: PartialFunction[BSONValue, JsValue] = { 
    case dt: BSONDateTime => Json.obj("$date" -> dt.value) 
} 

私のバージョンは、次のようになりなければならないでしょう:

val partialWrites: PartialFunction[BSONValue, JsValue] = { 
    case dt: BSONDateTime => 
     JsString(Instant.ofEpochMilli(dt.value).toString) 
} 

は、このビットを無効にすることが可能ですか?

私は手動で特定を選ぶとき、私だけでなく、私はのJSObjectにBSONDocumentを変換する際JsValueにBSONDateTime変換は常に動作する必要があることに注意したいのですが...

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"} 
    } 

} 

を実験を作成しました既知の特性。これは、私の例のプロパティ "something"が任意の名前を持ち、サブドキュメントにも現れることを意味します。

BTW:私は通常、私のPlayプロジェクトでBSONコレクションを使用していますが、とにかくこのケースで違いはないと思います。

編集

私はWrites[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}} 
    } 
} 

答えて

2

、BSON値はinstances of Writes[T]を使用してJSONを再生するために変換されます。

ここで暗黙的な範囲で自分自身のWrites[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 
+0

ありがとうございました。あなたが提案したようなWrites [BSONDateTime]を実装しましたが、無視されているようです。私の質問の編集を参照してください。私は何とかBSONDocumentFormatを使うからだと思っています。あなたはなにか考えはありますか? – Nick

+0

'println(s" writer = $ {暗黙的に[Writes [BSONDateTime]]} ")' – cchantep

+0

プリント: 'writer = play.api.libs.json.Writes $$ anon $ 6 @ b9c81b0' – Nick

関連する問題