【问题标题】:How to convert Slick result in desired format?如何将 Slick 结果转换为所需格式?
【发布时间】:2019-09-18 23:46:15
【问题描述】:

我有 Person 类型的域对象,它在案例类中定义如下:

case class Person(personName: String, personAge: Int, personId: Long = 0)

对应的查询表如下:

final case class PersonTable(tag: Tag) extends Table[Person](tag, "people") {

  def personId = column[Long]("person_id", O.AutoInc, O.PrimaryKey)

  def personName = column[String]("person_name")

  def age = column[Int]("person_age")

  def * = (personName, age, personId).mapTo[Person]
}

我有 Address 类型的域对象,它在 case 类中定义如下:

case class Address(houseNumber: Int, street: String
, state: String, ownerId: Long, id: Long = 0)

其对应的表类定义如下。人和地址是一对多的关系(一个人可以有多个地址,但一个地址只属于一个人

final case class AddressTable(tag: Tag) extends Table[Address](tag, "addresses") {
  def houseNumber = column[Int]("house_number")

  def street = column[String]("street_name")

  def state = column[String]("state_name")

  def addressId = column[Long]("address_id", O.PrimaryKey, O.AutoInc)

  def ownerId = column[Long]("owner_id")

  def owner = foreignKey("owner_fk", ownerId, TableQuery[PersonTable])(_.personId, onDelete = ForeignKeyAction.Cascade)

  def * = (houseNumber, street, state, ownerId, addressId).mapTo[Address]
}

我想从基于 Akka-http 的 REST API 返回以下类型的 JSON 结果(地址应作为数组返回):

{
    "name": "shekhar",
    "age": 30,
    "id": 1234,
    "addresses": [{
            "house_number": 1,
            "street": "water street",
            "state": "foo bar",
            "owner_id": 1234,
            "address_id": 9874
        },
        {
            "house_number": 99,
            "street": "foo bar street",
            "state": "foo disk state",
            "owner_id": 1234,
            "address_id": 007
        }
    ]
}

为了得到这个结果,我使用 Slick 编写了如下所示的查询:

  val peopleQueries = TableQuery[PersonTable]
  val addressQueries = TableQuery[AddressTable]
  val query = peopleQueries.filter(_.personName === "Shekhar") joinLeft addressQueries on (_.personId === _.ownerId)
  val futureResultData = db.run(query.result)

我在以下结构中得到结果(每个地址都重复个人详细信息):

Vector(
  (Person("shekhar",30,1234),
    Some(Address(1,"Water Street","foo bar",1234,9874))
  )
  , (Person("shekhar",30,1234),
    Some(Address(99,"foo bar street","foo disk state",1234,007))
  )
)

要将上述内容转换为预期的 JSON 格式,我可以等到 DB 查询运行并编写一些 Scala 代码以提供所需的格式,但这会阻止请求,直到此后处理完成(如果我是,请纠正我错了)。

我的代码如下所示:

futureResultData.onComplete {
  case Success(data) => // code to bring data in desired format
}

我想知道是否有任何方法可以以异步/非阻塞方式获得结果


感谢Pedro,我找到了解决这个问题的办法。

对我有用的解决方案如下:

futureResultData.map( x => {
        x.groupBy(_._1).mapValues(_.map(_._2.get))
})

【问题讨论】:

  • 您可以映射未​​来并与之合作
  • @PedroCorreiaLuís 你能提供一些关于如何做的指针/提示吗?我读了这篇关于“映射未来”的文章,但我无法清楚地理解它blog.knoldus.com/map-flatmap-on-futures-options-in-scala
  • 你可以把未来想象成一种奇怪的集合,它只包含一个元素。其他一切都由Future 类的魔力完成。所以mapflatMap 就像他们在Seq 上一样工作。

标签: scala akka h2 akka-http slick-3.0


【解决方案1】:
futureResultData.map {
  _.transformInDesiredFormat // code to bring data in desired format
}

如果您发布转换的实际代码,我可以为您提供更多帮助

Future 是 monad,所以当你映射时,你使用的是那个未来的东西,如果你有一个 Future[Int] 并且你映射了那个 Future,那么你在映射中使用 Int。

例子:

val aFuture = Future.successful(1)
aFuture.map(f=>  f+ 1)

【讨论】:

  • 感谢您的回答。它帮助我更好地理解事物。我编写了以下代码以获得所需的结果,但我不确定它是否会阻塞线程或者它将在 FutureResultData.groupBy(._1).mapValues(.map(_._2 .get))
  • 与您分享实际代码的最佳方式是什么? GitHub?
  • @Shekhar 是的 GitHub
猜你喜欢
  • 2021-10-24
  • 1970-01-01
  • 2021-04-25
  • 2018-12-24
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-05
相关资源
最近更新 更多