For simplification let's say I have three tables:
val postTable = TableQuery[Posts]
val postTagTable = TableQuery[PostTags]
val tagTable = TableQuery[Tags]
One post can have multiple tags and postTagTable
just contains the relation.
Now I could query the posts and tags like this:
val query = for {
post <- postTable
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
Which would give me a Future[Seq[(Post, Seq(Tag))]]
.
So far so good.
But what if I want to add pagination for the posts?
Since one Post
can have multiple Tags
with the above query, I don't know how many rows to take
from the query, in order to get, let's say, 10 Posts
.
Does anyone know a good way of getting the same result with a specific number of Posts in a single query?
I am actually not even sure how I would approach this in native SQL without nested queries, so if someone has a suggestion in that direction I would also be glad to hear it.
Thanks!
EDIT
Just so you know, what kind of query I am currently doing:
val pageQuery = postTable drop(page * pageSize) take(pageSize)
val query = for {
pagePost <- pageQuery
post <- postTable if pagePost.id === post.id
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
But this obviously results in a nested query. And this is what I would like to avoid.
EDIT 2
Another 2-query solution that would be possible:
val pageQuery = postTable drop(page * pageSize) map(_.id) take(pageSize)
db.run(pageQuery.result) flatMap {
case ids: Seq[Int] =>
val query = for {
post <- postTable if post.id inSetBind ids
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
}
But this would take two trips to the database and uses the in
operator, so it's probably not as good as the join query.
Any suggestions?