Play Framework:类型不匹配JsValue/JsValueWrapper

j3d*_*j3d 3 json scala playframework

我需要转换这个JSON

{ "matchItem": { "collection": { "fieldName": [ "value1", "value2" ] } } }
Run Code Online (Sandbox Code Playgroud)

这个MongoDB投影:

{ "collection": { "$elemMatch": { "fieldName": "value1", "fieldName": "value2" } }
Run Code Online (Sandbox Code Playgroud)

以下是我的代码:

def toProjection(json: JsValue) = {
  json.getOpt(__ \ "matchItem").map { value =>
    val obj = value.as[JsObject]
    for (key <- obj.keys) { obj.getOpt(__ \ key).map { matchObj =>
      for (matchKey <- matchObj.as[JsObject].keys) { matchObj.getOpt(__ \ matchKey).map { items =>
        val fields = items.as[Seq[JsValue]].map(item => (matchKey -> item))
        seq += key -> Json.obj("$elemMatch" -> Json.obj(fields))
      }}
    }}
  }
  if (seq.length > 0) JsObject(seq) else json
}

val json = """{ "matchItem": { "collection": { "fieldName": [ "value1", "value2" ] } } }"""
val proj = toProjection(json)
Run Code Online (Sandbox Code Playgroud)

此代码无法编译,我总是收到以下错误消息:

[error] /home/j3d/Projects/test/app/services/Test.scala:82: type mismatch;
[error]  found   : Seq[(String, play.api.libs.json.JsValue)]
[error]  required: (String, play.api.libs.json.Json.JsValueWrapper)
[error]                 seq += fieldMaps.fromPublic(key) -> Json.obj("$elemMatch" -> Json.obj(fields))
[error]                                                                                       ^
Run Code Online (Sandbox Code Playgroud)

我有点迷茫.我知道Json.obj是一个构建JsObject实例的辅助方法:

JsObject(Seq(
  "key1" -> JsString("value1"),
  "key2" -> JsString("value2")
  ...
))
Run Code Online (Sandbox Code Playgroud)

......相当于:

Json.obj("key1" -> "value1", "key2" -> "value2")
Run Code Online (Sandbox Code Playgroud)

在我上面的代码中,fields值是Seq[(String, play.api.libs.json.JsValue)]...所以我不明白为什么它不起作用.任何帮助将非常感激.

j3d*_*j3d 5

这是解决方案:

def toProjection(json: JsValue) = {
  json.getOpt(__ \ "matchItem").map { value =>
    val obj = value.as[JsObject]
    for (key <- obj.keys) { obj.getOpt(__ \ key).map { matchObj =>
      for (matchKey <- matchObj.as[JsObject].keys) { matchObj.getOpt(__ \ matchKey).map { items =>
        val fields = items.as[Seq[JsValue]].map(item => (matchKey -> item))
     // seq += key -> Json.obj("$elemMatch" -> Json.obj(fields))
        seq += key -> Json.obj("$elemMatch" -> JsObject(fields))
      }}
    }}
  }
  if (seq.length > 0) JsObject(seq) else json
}
Run Code Online (Sandbox Code Playgroud)

更换Json.obj(fields)用JsObject(fields)的伎俩.

我希望它有所帮助.