【问题标题】:Mapping a sequence of results from Slick monadic join to Json将 Slick monadic join 的一系列结果映射到 Json
【发布时间】:2016-04-03 20:51:44
【问题描述】:

我正在使用带有 Slick 3.1.x 的 Play 2.4,特别是 Slick-Play plugin v1.1.1。首先,一些上下文...我在 DAO 中有以下搜索/过滤方法,它将 4 个模型连接在一起:

  def search(
              departureCity: Option[String],
              arrivalCity: Option[String],
              departureDate: Option[Date]
            ) = {
    val monadicJoin = for {
      sf <- slickScheduledFlights.filter(a =>
              departureDate.map(d => a.date === d).getOrElse(slick.lifted.LiteralColumn(true))
            )
      fl <- slickFlights if sf.flightId === fl.id
      al <- slickAirlines if fl.airlineId === al.id
      da <- slickAirports.filter(a =>
              fl.departureAirportId === a.id &&
              departureCity.map(c => a.cityCode === c).getOrElse(slick.lifted.LiteralColumn(true))
            )
      aa <- slickAirports.filter(a =>
              fl.arrivalAirportId === a.id &&
              arrivalCity.map(c => a.cityCode === c).getOrElse(slick.lifted.LiteralColumn(true))
            )
    } yield (fl, sf, al, da, aa)

    db.run(monadicJoin.result)
  }

这个的输出是一个包含序列的向量,例如:

Vector(
  (
    Flight(Some(1),123,216,2013,3,1455,2540,3,905,500,1150),
    ScheduledFlight(Some(1),1,2016-04-13,90,10),
    Airline(Some(216),BA,BAW,British Airways,United Kingdom),
    Airport(Some(2013),LHR,Heathrow,LON,...),
    Airport(Some(2540),JFK,John F Kennedy Intl,NYC...)
  ), 
  (
    etc ...
  )
)

我目前通过在 Map 上调用 .toJson 并插入此 Vector(下面的 results 参数)在控制器中呈现 JSON,如下所示:

 flightService.search(departureCity, arrivalCity, departureDate).map(results => {
     Ok(
        Map[String, Any](
          "status" -> "OK",
          "data" -> results
        ).toJson
     ).as("application/json")
 })

虽然这种方法有效,但它会产生 output in an unusual format;每个结果对象内的结果数组(行)连接嵌套在具有键的对象内:“_1”、“_2”等。

所以问题是:我应该如何进行重组?

在 Slick 文档中似乎没有任何内容专门涵盖这种情况。因此,我将不胜感激有关重构此向量向量的最佳方法的一些输入,以重命名每个连接,甚至将其展平并仅保留某些字段?

这是最好在返回之前在 DAO 搜索方法中完成(通过以某种方式映射它?)还是在我从搜索方法中获取未来结果向量之后在控制器中完成?

或者我想知道是否最好将这种突变完全抽象到其他地方,也许使用transformer

【问题讨论】:

    标签: json playframework slick playframework-2.4 slick-3.0


    【解决方案1】:

    你需要JSON Reads/Writes/Format Combinators

    首先,您的所有课程都必须拥有Writes[T]FlightScheduledFlightAirlineAirport)。 简单的方法是使用 Json 宏

    implicit val flightWrites: Writes[Flight] = Json.writes[Flight]
    implicit val scheduledFlightWrites: Writes[ScheduledFlight] = Json.writes[ScheduledFlight]
    implicit val airlineWrites: Writes[Airline] = Json.writes[Airline]
    implicit val airportWrites: Writes[Airport] = Json.writes[Airport] 
    

    您还必须为 Vector 项目实现 OWrites[(Flight, ScheduledFlight, Airline, Airport, Airport)]。例如:

    val itemWrites: OWrites[(Flight, ScheduledFlight, Airline, Airport, Airport)] = (
      (__ \ "flight").write[Flight] and
      (__ \ "scheduledFlight").write[ScheduledFlight] and
      (__ \ "airline").write[Airline] and
      (__ \ "airport1").write[Airport] and
      (__ \ "airport2").write[Airport]
    ).tupled
    

    将整个Vector 写成JsAray 使用Writes.seq[T]

    val resultWrites: Writes[Seq[(Flight, ScheduledFlight, Airline, Airport, Airport)]] = Writes.seq(itemWrites)
    

    我们必须回复您的数据

    flightService.search(departureCity, arrivalCity, departureDate).map(results => 
      Ok(
        Json.obj(
          "status" -> "Ok", 
          "data" -> resultWrites.writes(results)
        )
     )
    

    【讨论】:

    • 非常感谢您的详细回复。我已经为所有使用 Json 宏的类设置了Writes[T],它只是从连接查询返回的向量,我不确定如何处理。目前,DAO 中的搜索方法只是返回一个包含上述对象序列的通用 Vector。我是否需要定义一个新对象作为结果向量的载体,在其中添加Writes.seq[T] 类型的resultWrites val?否则这应该去哪里?
    • 好的,通过在控制器中对flightService.search 的调用添加您建议的内容,让它工作。我不相信这是正确的地方,我猜val itemWrites: OWrites...val resultWrites: Writes... 可以通过特征混合在一起。将它放在控制器中感觉不对,但同样定义一个伪模型对象来保存结果序列也没有任何意义。无论如何,再次感谢您的指导,这是一个很大的帮助。
    • 你可以定义你的伪模型,但你必须实现自己的写入。 Writes.tupled 只是 Tuple 实现的这种伪模型的编写者。您的编写很简单,更复杂我尝试将外部控制器操作移至仅用于测试。您可以将这个写入伴随对象(如果控制器被实现为类)进行一次初始化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-02
    • 2012-11-04
    • 2017-06-24
    相关资源
    最近更新 更多