我正在使用Scala编写Play 2.3.2应用程序。 我使用ReactiveMongo来访问我的mongoDB数据库。
我有一个名为recommendation.advices的集合,它将所有建议存储到用户。
文件格式如下:
{
"_id" : ObjectId("54475f434be669af141677b7"),
"id" : "b8e84cb9-4b3a-4c6c-b01d-af276747e4ad",
"user" : {
"id" : "",
"email" : "luigi@gmail.com"
},
"output" : [
{
"tag" : "Vegetable:Carrots - alberto@gmail.com",
"score" : 0
},
{
"tag" : "Paper Goods:Liners - Baking Cups",
"score" : 0
},
{
"tag" : "Vegetable:Carrots - Jumbo",
"score" : 0
},
{
"tag" : "Paper Goods:Lialberto- Baking Cups",
"score" : 0
}
],
"date" : 1413963587328,
"type" : "system",
"clicked" : true
}
现在我正在我的控制器中编写一个方法,它返回"clicked": true
的所有数据,我想以下列形式返回一个Json:
{"idR": "b8e84cb9-4b3a-4c6c-b01d-af276747e4ad",
"user" : {
"id" : "",
"email" : "luigi@gmail.com"
},
"tags" : [
{
"tag" : "Vegetable:Carrots - alberto@gmail.com",
"score" : 0
},
{
"tag" : "Paper Goods:Liners - Baking Cups",
"score" : 0
},
{
"tag" : "Vegetable:Carrots - Jumbo",
"score" : 0
},
{
"tag" : "Paper Goods:Lialberto- Baking Cups",
"score" : 0
}
]
}
我怎样才能发挥其作用?
我尝试按以下方式实现该方法:
def clickedAdvises = Action.async {
val query = Json.obj("clicked" -> true)
Advices.find(query).toList flatMap { advices =>
val results = for(el <- advices) yield Json.obj("idR" -> el.id, "user" -> el.user, "tags" -> el.output)
Future{Ok(Json.obj("results" -> results))}
}
}
el.output是List[(Tag, Double)],
,对于Tag我已经定义了格式化程序。
但是编译器给了我以下错误:
[error] /Users/alberto/git/bdrim/modules/recommendation-system/app/recommendationsystem/controllers/StatisticsController.scala:111: type mismatch;
[error] found : List[(recommendationsystem.models.Tag, Double)]
[error] required: play.api.libs.json.Json.JsValueWrapper
[error] val results = for(el <- advices) yield Json.obj("idR" -> el.id, "user" -> el.user, "tags" -> el.output)
[error] ^
[error] /Users/alberto/git/bdrim/modules/recommendation-system/app/recommendationsystem/controllers/StatisticsController.scala:111: type mismatch;
[error] found : List[(recommendationsystem.models.Tag, Double)]
[error] required: play.api.libs.json.Json.JsValueWrapper
[error] val results = for(el <- advices) yield Json.obj("idR" -> el.id, "user" -> el.user, "tags" -> el.output)
[error] ^
[error] one error found
我该如何解决?
答案 0 :(得分:1)
错误是不言自明的:
您需要JsValue
,而不是List[(recommendationsystem.models.Tag, Double)]
,output
类Advice
字段显示Tag
字段。
您拥有toJson
类的格式化程序这一事实并不会改变这种情况,首先是因为您拥有的是元组列表,而不是单个标记,其次是因为格式化程序仅在您使用{{{ 1}}和fromJson
宏。
所以你需要的是以某种方式将这个List
元组转换为JsValue
。
JsArray
对应于JSON列表。如果你看一下它的代码
case class JsArray(value: Seq[JsValue] = List()) extends JsValue
您发现可以将Seq
JsValue
传递给它。因此,您需要以某种方式将(recommendationsystem.models.Tag, Double)
的元组转换为JsObject
(对应于JSON对象)。您只需使用以下代码即可完成此操作:
JsObject(Seq(
("tag", tag),
("score", score)
))
或使用Json.obj
作为帮助工厂mehtod来构建JsObject
。
所以代码将是:
val results = for {
el <- advices
} yield
Json.obj(
"idR" -> el.id,
"user" -> el.user,
"tags" -> Json.arr(el.output.map(it => Json.obj((it._1, it._2)).asInstanceOf[JsValueWrapper]): _*)
)
如果您引用Play Doc about JSON,您将看到可以使用play.api.libs.json.Json.toJson
方法将对象转换为json或从json转换对象。
为了做到这一点,你需要为你的类隐式编写器,这是非常简单的。
有一些宏助手,例如Json.writes
宏可以帮助您为类创建一个编写器。这个机制是递归的,所以如果你有所需的所有类的隐式编写器,那么你只需调用Json.toJson(advice)
并获得结果。
所以我建议你开始为你的建议课写一个隐含的作家:
import play.api.libs.json._
implicit def adviceWriter = Json.writes[Advice]
然后尝试
Json.toJson(advice)
然后编译代码,你将得到编译错误,因为你需要编写所有需要的类。继续为他们提供一个编写器,直到你没有编译错误!
这使代码更清晰,更简洁,更集中,因为实际转换为Json不会污染实际代码。此外,您可以重用代码而无需显式执行任何操作。您只需要通过导入并使用Json.toJson
和Json.fromJson
方法将隐式编写者和读者带入您的上下文。
答案 1 :(得分:0)
我认为你应该在将el.output插入jsObject
之前将其转换为JsObject答案 2 :(得分:0)
您确定可以通过el
之类的内容调用el.id
对象吗?它不是JavaScript,即使它是JsValue,也应该由(el \ "id")
调用。
我不太确定,但尝试使用el(id)
来调用它并插入JsObject
的值
Json.obj("idR" -> el(id))