0

我有一个预先格式化的 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 中,我猜测序列化程序/案例类在这里不是正确的解决方案。当然我可以留下这里的东西——但我想知道是否有一种方法可以更类似于 Scala 并且对 CPU 更友好。

4

1 回答 1

0

可以选择通过处理 MongoDB 类来扩展 Scalatra 的渲染管道。以下两条路线作为示例。他们返回 aMongoCursor和 aDBObject作为结果。我们要将它们转换为字符串。

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

为了处理这些类型,我们需要定义一个偏函数来处理转换并设置适当的内容类型。

有两种情况,第一种处理 a DBObject。内容类型设置为“application/json”,并通过调用该toString方法将对象转换为字符串。第二种情况处理一个MongoCursor. 由于它实现TraversableOncemap可以使用的功能。

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.

是工作示例项目中的先前代码。

于 2013-08-25T20:19:35.813 回答