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_id
是 Column[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
)}
我在做微博系统。像 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_id
是 Column[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
)}