You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Play Framework与Mongo Scala Driver:如何解析Document为JSON?

解决Mongo Scala Driver查询结果转Play JSON的问题

嘿,我来帮你搞定这个Mongo Scala Driver查询结果转Play JSON的问题!你现在的代码只是通过subscribe打印查询结果,没法直接把结果返回给前端,咱们得调整一下代码结构,适配Play的异步模型,同时完成Document到JSON的转换。

第一步:把Mongo查询转换成Future集合

Mongo Scala Driver的Observable可以转换成Future,这样更贴合Play框架的异步Action模式。咱们先重构getAllProcess方法,让它返回Future[List[Document]]:

import org.mongodb.scala._
import org.mongodb.scala.model.Filters.equal
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

// 重构后的方法,返回Future包裹的Document列表
def getAllProcess(userId: String): Future[List[Document]] = {
  getCollection(COMPANY_FORM)
    .find(equal("userId", userId))
    .toList() // 将Observable转为Observable[List[Document]]
    .toFuture() // 最终转为Future[List[Document]]
}

第二步:把Document转换成Play JSON

这里有两种常用方式,你可以根据需求选择:

方式1:直接转换Document为Play JsValue(快速灵活)

Play的Json API可以直接把Map转成JSON,而Document可以通过toMap()方法转为键值对Map,咱们写个转换函数:

import play.api.libs.json._

// 把单个Document转成Play的JsValue
private def docToJson(doc: Document): JsValue = {
  val fieldPairs = doc.toMap.map { case (key, value) =>
    key -> Json.toJson(value)
  }
  JsObject(fieldPairs)
}

然后在Play的Controller里写Action,返回JSON响应:

import play.api.mvc._

class ProcessController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {
  def fetchAllProcesses(userId: String) = Action.async { implicit request =>
    getAllProcess(userId)
      .map { docs =>
        // 把所有Document转成JSON列表,然后返回Ok响应
        val jsonList = docs.map(docToJson)
        Ok(Json.toJson(jsonList))
      }
      .recover { case ex =>
        // 处理查询异常,返回错误信息给前端
        InternalServerError(Json.obj("error" -> s"查询失败: ${ex.getMessage}"))
      }
  }
}

方式2:用Case Class映射(类型安全,推荐)

如果你的Document结构固定,用Case Class来映射会更安全,还能利用Play的自动JSON格式化功能:

首先定义和Document结构匹配的Case Class,以及对应的JSON Format:

import play.api.libs.json._

// 假设你的Process文档有这些字段,根据实际情况调整
case class Process(
  userId: String,
  processName: String,
  createTime: Long,
  status: String
)

// 自动生成JSON的序列化/反序列化规则
object Process {
  implicit val processFormat: OFormat[Process] = Json.format[Process]
}

然后写一个从Document到Process的转换函数:

private def docToProcess(doc: Document): Process = {
  Process(
    userId = doc.getString("userId"),
    processName = doc.getString("processName"),
    createTime = doc.getLong("createTime"),
    status = doc.getString("status")
  )
}

最后在Controller里使用:

def fetchAllProcesses(userId: String) = Action.async { implicit request =>
  getAllProcess(userId)
    .map { docs =>
      val processes = docs.map(docToProcess)
      // 直接把Process列表转成JSON
      Ok(Json.toJson(processes))
    }
    .recover { case ex =>
      InternalServerError(Json.obj("error" -> s"查询失败: ${ex.getMessage}"))
    }
}

为什么不用原来的subscribe?

原来的subscribe是回调式的处理,没法直接和Play的Action.async需要返回Future[Result]的模型结合。转换成Future之后,我们可以更优雅地处理异步结果,同时统一管理异常,把错误信息返回给前端,而不是只在控制台打印。

内容的提问来源于stack exchange,提问作者Azoulay Jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:06:12