JsonExtensions
Tôi thường có một đối tượng JsExtensions trong ứng dụng của mình trông giống như sau:
import reactivemongo.bson.BSONObjectID
object JsonExtensions {
import play.api.libs.json._
def withDefault[A](key: String, default: A)(implicit writes: Writes[A]) = __.json.update((__ \ key).json.copyFrom((__ \ key).json.pick orElse Reads.pure(Json.toJson(default))))
def copyKey(fromPath: JsPath,toPath:JsPath ) = __.json.update(toPath.json.copyFrom(fromPath.json.pick))
def copyOptKey(fromPath: JsPath,toPath:JsPath ) = __.json.update(toPath.json.copyFrom(fromPath.json.pick orElse Reads.pure(JsNull)))
def moveKey(fromPath:JsPath, toPath:JsPath) =(json:JsValue)=> json.transform(copyKey(fromPath,toPath) andThen fromPath.json.prune).get
}
Đối với một mô hình đơn giản
case class SOUser(name:String,_id:BSONObjectID)
bạn có thể viết serializer / deserializer json của mình như thế này:
object SOUser{
import play.api.libs.json.Format
import play.api.libs.json.Json
import play.modules.reactivemongo.json.BSONFormats._
implicit val soUserFormat= new Format[SOUser]{
import play.api.libs.json.{JsPath, JsResult, JsValue}
import JsonExtensions._
val base = Json.format[SOUser]
private val publicIdPath: JsPath = JsPath \ 'id
private val privateIdPath: JsPath = JsPath \ '_id \ '$oid
def reads(json: JsValue): JsResult[SOUser] = base.compose(copyKey(publicIdPath, privateIdPath)).reads(json)
def writes(o: SOUser): JsValue = base.transform(moveKey(privateIdPath,publicIdPath)).writes(o)
}
}
đây là những gì bạn nhận được trong bảng điều khiển:
scala> import reactivemongo.bson.BSONObjectID
import reactivemongo.bson.BSONObjectID
scala> import models.SOUser
import models.SOUser
scala> import play.api.libs.json.Json
import play.api.libs.json.Json
scala>
scala> val user = SOUser("John Smith", BSONObjectID.generate)
user: models.SOUser = SOUser(John Smith,BSONObjectID("52d00fd5c912c061007a28d1"))
scala> val jsonUser=Json.toJson(user)
jsonUser: play.api.libs.json.JsValue = {"name":"John Smith","id":"52d00fd5c912c061007a28d1","_id":{}}
scala> Json.prettyPrint(jsonUser)
res0: String =
{
"name" : "John Smith",
"id" : "52d00fd5c912c061007a28d1",
"_id" : { }
}
scala> jsonUser.validate[SOUser]
res1: play.api.libs.json.JsResult[models.SOUser] = JsSuccess(SOUser(John Smith,BSONObjectID("52d00fd5c912c061007a28d1")),/id)
Áp dụng điều này cho ví dụ của bạn
val _personReads: Reads[JsObject] = (
(__ \ 'id).read[String] ~
(__ \ 'name).read[String] ~
(__ \ 'surname).read[String]
).reduce
Không biên dịch theo mặc định, tôi đoán bạn muốn viết:
val _personReads: Reads[(String,String,String)] = (
(__ \ 'id).read[String] ~
(__ \ 'name).read[String] ~
(__ \ 'surname).read[String]
).tupled
trong trường hợp đó, bạn có thể làm như sau
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.modules.reactivemongo.json.BSONFormats._
import reactivemongo.bson.BSONObjectID
def copyKey(fromPath: JsPath,toPath:JsPath ) = __.json.update(toPath.json.copyFrom(fromPath.json.pick))
val json = """{
"id": "ff59ab34cc59ff59ab34cc59",
"name": "Joe",
"surname": "Cocker"
}"""
val originaljson = Json.parse(json)
val publicIdPath: JsPath = JsPath \ 'id
val privateIdPath: JsPath = JsPath \ '_id \ '$oid
val _personReads: Reads[(BSONObjectID,String,String)] = (
(__ \ '_id).read[BSONObjectID] ~
(__ \ 'name).read[String] ~
(__ \ 'surname).read[String]
).tupled
val personReads=_personReads.compose(copyKey(publicIdPath,privateIdPath))
originaljson.validate(personReads)
// yields res5: play.api.libs.json.JsResult[(reactivemongo.bson.BSONObjectID, String, String)] = JsSuccess((BSONObjectID("ff59ab34cc59ff59ab34cc59"),Joe,Cocker),/id)
hoặc ý bạn là bạn muốn chuyển giá trị của khóa id thành _id \ $oid
có thể được thực hiện với
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.modules.reactivemongo.json.BSONFormats._
import reactivemongo.bson.BSONObjectID
def copyKey(fromPath: JsPath,toPath:JsPath ) = __.json.update(toPath.json.copyFrom(fromPath.json.pick))
val json = """{
"id": "ff59ab34cc59ff59ab34cc59",
"name": "Joe",
"surname": "Cocker"
}"""
val originaljson = Json.parse(json)
val publicIdPath: JsPath = JsPath \ 'id
val privateIdPath: JsPath = JsPath \ '_id \ '$oid
originaljson.transform(copyKey(publicIdPath,privateIdPath) andThen publicIdPath.json.prune)
Bạn không thể có BSONObjectID trong đó bây giờ vì bạn đang thao tác đối tượng từ cấu trúc phân cấp kiểu JsValue. Khi bạn chuyển json tới Reativemongo, nó sẽ được chuyển đổi thành BSONValue. Một JsObject sẽ được chuyển đổi thành một BSONDocument. nếu JsObject chứa đường dẫn cho _id \ $oid
đường dẫn này sẽ được tự động chuyển đổi thành BSONObjectId và nó sẽ được lưu trữ dưới dạng ObjectID trong mongodb.