Для упрощения скажем, у меня есть три таблицы:
val postTable = TableQuery[Posts]
val postTagTable = TableQuery[PostTags]
val tagTable = TableQuery[Tags]
У одного сообщения может быть несколько тегов, а postTagTable
содержит только отношение.
Теперь я мог запросить сообщения и теги следующим образом:
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))
}
}
Что дало бы мне Future[Seq[(Post, Seq(Tag))]]
.
Все идет нормально.
Но что, если я хочу добавить нумерацию страниц для сообщений? Так как один Post
может иметь несколько Tags
с приведенным выше запросом, я не знаю, сколько строк нужно take
из запроса, чтобы получить, скажем, 10 Posts
.
Кто-нибудь знает хороший способ получить тот же результат с определенным количеством сообщений в одном запросе?
На самом деле я даже не уверен, как бы я подошел к этому в собственном SQL без вложенных запросов, поэтому, если у кого-то есть предложение в этом направлении, я также был бы рад его услышать.
Спасибо!
ИЗМЕНИТЬ
Просто чтобы вы знали, какой запрос я сейчас делаю:
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))
}
}
Но это, очевидно, приводит к вложенному запросу. А вот этого хотелось бы избежать.
ИЗМЕНИТЬ 2
Другое решение с двумя запросами, которое было бы возможно:
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))
}
}
}
Но это потребует двух обращений к базе данных и использования оператора in
, поэтому, вероятно, это не так хорошо, как запрос на соединение.
Какие-либо предложения?
groupBy
Слика в этом случае не помогает? Если вы сделаетеgroupBy
по почте по запросу, а затемtake
? - person User   schedule 15.08.2015