implement 2-stage mapReduce paginator
parent
c25c4d9698
commit
4aacd776ca
|
@ -33,26 +33,40 @@ final class Adapter[A: BSONDocumentReader](
|
|||
.list[A](length, readPreference)
|
||||
}
|
||||
|
||||
/*
|
||||
* because mongodb mapReduce doesn't support `skip`, slice requires to queries.
|
||||
* The first one gets the IDs with `skip`.
|
||||
* The second one runs the mapReduce on these IDs.
|
||||
* This avoid running mapReduce on many unnecessary docs.
|
||||
* NOTE: Requires string ID.
|
||||
*/
|
||||
final class MapReduceAdapter[A: BSONDocumentReader](
|
||||
collection: Coll,
|
||||
selector: Bdoc,
|
||||
sort: Bdoc,
|
||||
runCommand: RunCommand,
|
||||
command: MapReduceAdapter.Command,
|
||||
command: Bdoc,
|
||||
readPreference: ReadPreference = ReadPreference.primary
|
||||
) extends AdapterLike[A] {
|
||||
|
||||
def nbResults: Fu[Int] = collection.countSel(selector, readPreference)
|
||||
|
||||
def slice(offset: Int, length: Int): Fu[List[A]] =
|
||||
runCommand(
|
||||
command(offset) ++ $doc("limit" -> (offset + length)),
|
||||
readPreference
|
||||
) map { res =>
|
||||
res.getAs[List[Bdoc]]("results").??(_ map implicitly[BSONDocumentReader[A]].read)
|
||||
collection.find(selector, $id(true))
|
||||
.sort(sort)
|
||||
.skip(offset)
|
||||
.list[Bdoc](length, readPreference)
|
||||
.dmap { _ flatMap { _.getAs[BSONString]("_id") } }
|
||||
.flatMap { ids =>
|
||||
runCommand(
|
||||
$doc(
|
||||
"mapreduce" -> collection.name,
|
||||
"query" -> $inIds(ids),
|
||||
"out" -> $doc("inline" -> true)
|
||||
) ++ command,
|
||||
readPreference
|
||||
) map { res =>
|
||||
res.getAs[List[Bdoc]]("results").??(_ map implicitly[BSONDocumentReader[A]].read)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object MapReduceAdapter {
|
||||
// offset -> doc
|
||||
type Command = Int => Bdoc
|
||||
}
|
||||
|
|
|
@ -36,27 +36,23 @@ final class StudyMultiBoard(
|
|||
* return the last mainline node.
|
||||
* Else, return the root node without its children.
|
||||
*/
|
||||
val command: MapReduceAdapter.Command = offset => $doc(
|
||||
"mapreduce" -> chapterColl.name,
|
||||
"map" -> """var node = this.root, child, result = {name:this.name,orientation:this.setup.orientation,tags:this.tags};
|
||||
Paginator(
|
||||
adapter = new MapReduceAdapter[ChapterPreview](
|
||||
collection = chapterColl,
|
||||
selector = selector,
|
||||
sort = $sort asc "order",
|
||||
runCommand = runCommand,
|
||||
command = $doc(
|
||||
"map" -> """var node = this.root, child, result = {name:this.name,orientation:this.setup.orientation,tags:this.tags};
|
||||
if (this.tags.filter(t => t.indexOf('White:') === 0 || t.indexOf('Black:') === 0).length === 2) {
|
||||
while(child = node.n[0]) { node = child };
|
||||
}
|
||||
result.fen = node.f;
|
||||
result.uci = node.u;
|
||||
emit(this._id, result)""",
|
||||
"reduce" -> """function(key, values) { return key; }""",
|
||||
"out" -> $doc("inline" -> true),
|
||||
"query" -> selector,
|
||||
"sort" -> $sort.asc("order"),
|
||||
"jsMode" -> true
|
||||
)
|
||||
Paginator(
|
||||
adapter = new MapReduceAdapter[ChapterPreview](
|
||||
collection = chapterColl,
|
||||
selector = selector,
|
||||
runCommand = runCommand,
|
||||
command = command
|
||||
"reduce" -> """function(key, values) { return key; }""",
|
||||
"jsMode" -> true
|
||||
)
|
||||
),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage
|
||||
|
|
Loading…
Reference in New Issue