Slick 3:使用 leftJoin 和 groupBy 计数 "OR NULL"

Slick 3: count "OR NULL" with leftJoin and groupBy

我在做微博系统。像 Twitter 一样,我想用“(1) Like Count”和“(2) 用户是否已经喜欢它?”来检索 post 数据。

我的数据库架构:
post (id: Int, title: String)
favorite (id: Int, post_id: Int, user_id: Int)

我可以在SQL中得到我想要的(假设用户id是1)

SELECT post.id, post.title, COUNT(favorite.id), COUNT(favorite.user_id = 1 OR NULL) FROM post 
  LEFT JOIN favorite ON post.id = favorite.post_id
  GROUP BY post.id

但是对于 Slick 3,我不知道如何在 (2) 上得到相同的结果。

Post.joinLeft(Fav).on(_.id  === _.postId)
    .groupBy(_._1)
    .map { case (post, group) => (
        post,
        group.map(_._2.map(_.id)).countDefined,  // (1) this works!
        group.map(_._2.???).countDefined   // (2) ?
    )}

如何查询?

更新: Fav 列的 Slick Schema(我使用了 slick-codegen)

val id: Rep[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
val userId: Rep[Int] = column[Int]("user_id")
val postId: Rep[Int] = column[Int]("post_id")

我不太确定这是否有效,但我记得之前做过类似的事情。

你现在可以试试这个(假设 favourite.user_idColumn[Option[Int]]),

Post.joinLeft(Fav)
  .on(_.id  === _.postId)
  .groupBy(_._1)
  .map({ case (post, group) => (
    post,
    group.map(_._2.map(_.id)).countDefined,
    group.filter({
      case (p, f) => f.user_id.isEmpty || f.user_id.filter(_ == 1).isDefined
    }).length
  )})

您可以通过更改以下行来消除 Sarvesh Kumar Singh 的答案中的编译错误(但是您会在 slick 3 上遇到运行时错误。1.X 和 3.2.X):

group.filter{
      case (p, f) => f.filter(_.userId === 1).isDefined
    }.length

因为 f 的类型是 Rep[Option[Favorite]] 你不能直接得到 f.userId 可用。

注意:当您尝试在 groupBy + filter 或 map 之后调用 length 函数时,slick 会引发运行时错误。您可以在此处跟踪问题 - https://github.com/slick/slick/issues/1355

您可以改用以下代码:

Post.joinLeft(Favorite)
  .on(_.id  === _.postId)
  .groupBy(_._1)
  .map{ case (post, group) => (
    post,
    group.map(_._2.map(_.id)).countDefined,
    group.map(_._2.filter(_.userId === 1).map(_.userId)).countDefined 
    )}