我将一个预格式化的JSON blob存储为MongoDB中的字符串,作为其中一个集合中的字段。目前在我的基于Scalatra的API中,我有一个前置过滤器,它使用JSON内容类型呈现我的所有响应。我如何返回内容的示例如下所示:
get ("/boxscore", operation(getBoxscore)) {
val game_id:Int = params.getOrElse("game_id", "3145").toInt
val mongoColl = mongoDb.apply("boxscores")
val q: DBObject = MongoDBObject("game_id" -> game_id)
val res = mongoColl.findOne(q)
res match {
case Some(j) => JSON.parseFull(j("json_body").toString)
case None => NotFound("Requested document could not be found.")
}
}
现在这确实有效。它似乎不是“Scala”做事的方式,我觉得这可以优化。对我来说令人担忧的部分是当我添加一个缓存层并且缓存没有达到时,我会花费额外的CPU时间来重新解析我已经在MongoDB中格式化为JSON的字符串:
JSON.parseFull(j("json_body").toString)
我必须从findOne()获取结果,在其上运行.toString,然后将其重新解析为JSON。有更优化的路线吗?由于JSON已经存储为MongoDB中的String,我猜测序列化器/案例类在这里不是正确的解决方案。当然,我可以留下这里的内容 - 但我想知道是否有一种方式可以更像Scala和CPU友好。
答案 0 :(得分:0)
可以选择扩展Scalatra的渲染管道,处理MongoDB类。以下两条路线就是一个例子。他们返回MongoCursor
和DBObject
作为结果。我们将把它们转换为字符串。
get("/") {
mongoColl.find
}
get("/:key/:value") {
val q = MongoDBObject(params("key") -> params("value"))
mongoColl.findOne(q) match {
case Some(x) => x
case None => halt(404)
}
}
为了处理我们需要定义部分函数的类型,它负责转换并设置适当的内容类型。
有两种情况,第一种处理DBObject
。内容类型设置为“application / json”,并通过调用toString
方法将对象转换为字符串。第二种情况处理MongoCursor
。由于它实现了TraversableOnce
,因此可以使用map
函数。
def renderMongo = {
case dbo: DBObject =>
contentType = "application/json"
dbo.toString
case xs: TraversableOnce[_] => // handles a MongoCursor, be aware of type erasure here
contentType = "application/json"
val ls = xs map (x => x.toString) mkString(",")
"[" + ls + "]"
}: RenderPipeline
(请注意以下类型定义:type RenderPipeline = PartialFunction[Any, Any]
)
现在需要将方法挂钩。处理完HTTP调用后,结果将转发到渲染管道以进行进一步转换。可以通过覆盖renderPipeline
中的ScalatraBase
方法来添加自定义处理。通过以下定义,首先调用renderMongo
函数:
override protected def renderPipeline = renderMongo orElse super.renderPipeline
这是处理MongoDB类型的基本方法。还有其他选项,例如使用json4s-mongo
。
Here是工作示例项目中的先前代码。