Narrator: Now, another extremely important feature
of a good API is to provide pagination.
So basically allowing the user
to only select a certain page of our results,
in case we have a lot of results.
So let's pretend that we have, for example,
1000 documents in a certain collection.
And we say that on each page we have 100 documents.
So that would mean that we'd have 10 pages, right?
So 10 times 100 is 1000.
And so based on that, how are we gonna implement pagination
using or query string?
Well, we will use the page and delimit fields.
So there will be a page field.
Let's say we want page two
and there will be a limit field.
And this limit here basically means the amount
of results that we want per page.
And that's actually setted here only to 10
and of course we have to correct this one here.
It's not a comma, but an and.
So page two and the limit 10.
Now going back to the example of 1000 results,
if the limit is 10, so only 10 results per page,
well then we're gonna have 100 pages
and in here we are then displaying page number 2
of these 100 pages.
Okay?
Now, we need now a way of implementing this using Mongoose.
So let's take a look at how we could do that
by going back to our code.
So feature number four,
Pagination.
All right,
And I will start by building an example query here
just like we did before.
So let's say that the query is equal query.
And now what kind of methods do we have
in order to implement pagination?
Well, the most useful one is skip
and I'm gonna explain what it does in a second,
so let's just put a random number here.
So skip and limit,
and let's put 10.
and so this limit here is actually exactly the same
as the limit that we defined in the query string.
So basically the amount of results
that we want in the query.
And then skip, that we have here, is the amount of results
that should be skipped before actually querying data.
All right, so again, this is just a placeholder here.
Let's go back to this example that we have here.
I'm just gonna copy this query string here.
so let's say that the user wants page number two
with 10 results per page.
That means that results one to 10 are on page one,
and 11 to 20 are on page 2.
Okay, and so what that means is that we want to skip
10 results before we actually start querying.
Okay.
So again, one to 10
are for page one
and then 11 to 20
are for page two,
and so on and so forth.
So 21 to 30 will be page three,
And so on and so forth.
And so we need to skip 10 results
in order to get to result number 11, right?
So to result number 11 which will the first one on page two.
Okay, and since it is page two that was requested,
well, again we need to skip 10 results
before we actually start page two.
Okay? Make sense?
And for example, if we requested page number three,
well then of course, 20 results would
first have to be skipped.
And so we will need some way
of calculating this skip value here.
So based basically on the page and the limit.
Now you might ask why I do not directly ask for the
skip value in the query string,
but that's because for the user this value here is
kind of abstract, okay?
It's way easier to simply say, "Well I want page number one,
"or I want page number five
"or I want like page number 10."
Okay, so for the user it's much easier
to not deal with skip values here
and all that stuff, the user wants to have it easy
and to just define a page.
Now before we can actually get started
calculating the skip value, we need to first get the page
and the limit from the query string
and we should also define some default values.
Okay, so that's basically
because we still want to have pagination
even if the user does not specify any page
or any limit.
Because for example let's say that we have a million results
in our database,
and then of course when the user does the request
we would not simply show all of these 10 million results.
That wouldn't be very user friendly, would it?
And so, I will define by default page number one
and a limit of let's say 100.
So that by default when a user requests all of the tours
in this example, then he only gets 100,
and not a million, all right?
So the page is of course request.query.page
and I'm now going to multiply it by one
which is just a nice trick to convert
a string to a number.
Okay, so maybe you noticed before that each time that we
actually put a number in a query string,
it will then be a string or a query object,
and so we need to fix that simply by multiplying by one.
Okay, and then by default, we want page number one.
All right?
And so this is a nice way in JavaScript
of basically defining default values.
And I'm sure you're familiar with that, right?
Anyway, the limit is on req.query.limit
times one again to convert it,
or the default of 100 that we just mentioned.
So ideally the user will only specify the page number
that he requests
and to not even bother with the page limit.
That's for more specific use cases.
Okay, and now all we need to do is to then define
so to calculate basically
that skip value that we just talked about here before.
And the best way of doing that is to go back to an example.
So again, let's say we are requesting page number three,
with the limit of 10.
and we see here for page number three the results are
from 21 to 30.
So it starts at result number 21, meaning that we need to
skip 20 results.
And 20 results is basically two times 10,
so two times this limit.
Okay, and from there we actually start getting a formula.
So two times ten is basically three minus one times 10.
And three is the page that we're on.
So that is our formula.
So page minus one
and so the previous page, basically,
times
the limit.
Okay, so I hope that made sense,
let's now replace these values here.
Skip
and limit of limit.
Okay?
So basically, this number here is all the results that
come before the page that we're actually requesting now.
So again, if we are requesting page number three
our results are gonna start at page number 21.
And so we wanna skip 20 results before that.
And so 20 results is
because we have 2 pages time 10 results on each,
Yeah, it's gonna be the page that we just requested.
So page here, minus one,
so the previous page times the number of results
on each page.
Okay, so that's the amount of documents that
are gonna be skipped.
Okay, so I hope that made sense.
Let's now go ahead and actually try this.
And since we only have so few results here
we need to test it with a really small limit.
So let's say that we only want three results per page,
and let's actually start on page number one.
So send it, and indeed now we only get
three results as you can see here.
So these three, let's see.
So The Forest Hiker,
The Sea Explorer,
and The City Wanderer.
Okay?
Let's try page number two,
and for some reason the postman keeps jumping around
each time that I change the URL.
Anyway, now we have The Park Camper,
The Snow Adventurer,
and The Sports Lover.
So you start seeing that we actually
now have different tours.
Okay?
And so we can kind of say that
our pagination here is already working.
Now the last page,
and we have now The Northern Lights,
The Wine Taster,
and The Star Gazer.
All right?
Now what if we try to go to page number four?
We already know that we only have nine tours,
and so on page number four there should be nothing.
Right?
So let's test that.
And indeed we get zero results.
But that is of course not ideal.
Okay, and so let's now go ahead and fix that
and basically kind of throw an error each time
the user selects a page that does not exist.
Because that's basically the situation here.
The user requested a page that simply does not exist.
We don't have enough results to have four pages
with three results.
Let's now do that,
and this will actually only happen
when there is a page on the query
and so let's actually create this if statement here.
So if request.query.page,
only in this case we will test if we are skipping more
tours than we actually have.
So let's get the amount of tours.
So number of tours is equal to,
and now we're actually going to learn a new method.
So a new method there is on the Tour model
which is called countDocuments.
Okay? And as the name says this is going to return
the number of documents, all right?
Actually it's gonna return a promise
but we then await the promise
and so it will then come back
with the result of the amount of tours.
Okay? And so if the number of documents that we skip
is greater than the number of documents that actually exists
well then that means that the page does not exist, alright?
That make sense?
So if skip is greater
than the number of tours,
and for now what I'm gonna do here is to throw a new error.
Okay?
So throw new error
this page does not exist.
Now why am I throwing an error here?
Well, simply because if I throw an error here
in the triblock which we are currently in,
it will then automatically
and immediately move on to the catch block,
and it will then send back this 404 kind of fail message.
Okay?
And so that's what we want for now.
Just keep in mind that we will implement much better
error handling a bit later in the course.
And actually right in the next section, okay?
But for now let's just keep it simple,
throw this error here
in case that we're trying to skip more documents
than we actually have.
Okay?
So this is the right case, let's send it here
and that's not the result that I expected
so let's go back
so right now our page is four
and the limit is three.
So the skip here would be three time three, so nine, okay?
And the number of tours is nine as well
and so skip is not greater than the number of tours
and therefore we don't get this error.
So what we need to do is to set it to greater or equal.
Okay, and so that should now work.
And that takes a long time,
and it did.
Now we get the fail status here
and a 404.
For some reason
this error is not showing up here
which it actually should.
But don't worry about that, that's not really important.
What matters is that it did actually enter our catch block,
and then send back this 404 response.
Everything else we're gonna implement a bit later.
Okay, and that's actually it.
So that's all the methods that we're gonna add to our query,
and so when we finally reach the next line of code here,
our query will then be awaited,
and return with the tours.
Okay, and at this point our query might actually look
something like
so something like this, something like
well what do we have here
we have sort, select,
so we might have sort,
and then some select there
we have also
skip
we have limit as well,
and so that's really kind of a big query.
And again, what allows us to that that is
that each of these methods here will always return
a new query that we can then chain on the next method
and the next method,
and the next method until we finally await the query
so that it can actually give us our documents.
Okay, so let's get rid of all these comments
and yeah, that's it for now.
For these features we're just gonna add one more
in the next lecture,
but that one is gonna be a bit different than these.
It's not gonna use one of these query methods, all right?
So I hope that over the last couple of lectures
you really learned the ins and outs
of querying data with Mongoose.
So of course, all of these methods that we used are not
only useful for these features that we implemented here.
You can really create all kinds of querys
that you can imagine for all kinds of applications.
So I showed you all the techniques here in this context
of these different API features,
but of course you're gonna be able to use them
all over your applications in the future, okay?
So I hope that was fun for you
and if it was, then let's move on now right to the next one.
See you!