-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pagination to Listings API #56
Comments
Was digging into this to figure out filtering work. It looks like the applications list page fetches data using this hook: It's hitting this backend endpoint: bloom/backend/core/src/applications/applications.controller.ts Lines 174 to 180 in ffb434a
which does some params validation and passes the limit + page info to the query params here:
|
Just recording some things I'm learning about the listings controller/service. The So urls like I can only see one (non-test) place where the
(After URL decoding, that looks like In any case, |
I got proof-of-concept pagination working using nestjs-typeorm-paginate, which is what we already use for Application pagination (thanks for the pointers @avaleske !). Here's a simplified version of
This was mostly straightforward; the only tricky bit was typeorm/typeorm#6691: "OrderBy expects propertyNames instead of column names." All this meant is that I had to switch |
Hmm, I'm hitting a bug with this
Someone on that other bug found a subquery workaround ( Note: I believe our existing |
Are the pages 0-indexed? |
No, they're 1-indexed; setting |
Recording where I got to: I got the subquery public async list(jsonpath?: string): Promise<Listing[]> {
let queryBuilder = this.getQueryBuilder().orderBy({
"listings.id": "DESC",
"units.maxOccupancy": "ASC",
})
let wrappingQueryBuilder = getConnection().createQueryBuilder().select("*").from("(" + queryBuilder.getQuery() + ")", "listings")
// I've confirmed that this new query is just 'SELECT * FROM (<old_query>) "listings"'
console.log(wrappingQueryBuilder.getQuery())
// This hack comes from https://github.com/typeorm/typeorm/issues/4015#issuecomment-691030543
// (To avoid "Cannot get entity metadata for the given alias" error)
wrappingQueryBuilder.expressionMap.mainAlias.metadata = wrappingQueryBuilder.connection.getMetadata(Listing)
// Need to cast this to include the Listing type
const newQueryBuilderRescoped = wrappingQueryBuilder as SelectQueryBuilder<Listing>
let listings = await paginate<Listing>(newQueryBuilderRescoped, {limit: 3, page: 10})
/*
This logs:
{
totalItems: 155,
itemCount: 0,
itemsPerPage: 52,
currentPage: 1
}
*/
console.log(listings.meta)
return []
} This workaround might be a dead end... |
I don't know if you saw this in the TypeORM documentation, but I just discovered that there are |
Although that throws a 500 unless you update the
by changing I'm curious how take is actually working. Does it do a limit on the join or does it just drop the extra results in code? If it's just dropping the extra results in code that's not ideal |
Thanks Austin for the pointer to https://typeorm.io/#/select-query-builder/using-pagination. I'm going to try that next, and will check if Before I try that, recording where I got to with the
Last state of my code using the public async list(jsonpath?: string): Promise<Listing[]> {
let listings = this.getQueryBuilder()
.orderBy({
"listings.id": "DESC",
"units.maxOccupancy": "ASC",
"preferences.ordinal": "ASC",
})
const wrappingQueryBuilder: SelectQueryBuilder<Listing> = getConnection()
.createQueryBuilder().select("*").from("(" + listings.getQuery() + ")", "listings")
// This hack comes from https://github.com/typeorm/typeorm/issues/4015#issuecomment-691030543
// (To avoid "Cannot get entity metadata for the given alias" error)
wrappingQueryBuilder.expressionMap.mainAlias.metadata = wrappingQueryBuilder.connection.getMetadata(Listing)
let rawListings = await paginateRaw<Listing>(wrappingQueryBuilder, {limit: 5, page: 1})
/*
This logs:
{
totalItems: 155,
itemCount: 5,
itemsPerPage: 5,
totalPages: 31
currentPage: 1
}
Which shows that pagination is working correctly.
But the cardinality is way off: there should only be 7 listings. I believe the 155 totalItems
comes from joining all the different tables (and so one listing now spans multiple rows
in the raw results.)
*/
console.log("paginateRaw metadata:")
console.log(rawListings.meta)
/*
This logs:
{
listings_id: 'aadf50b9-944d-4d3e-9494-585c8e04ca8b',
listings_created_at: 2021-06-18T15:08:30.894Z,
listings_updated_at: 2021-06-18T15:08:30.894Z,
...
}
Notice that the attributes in these raw results are in the form "listing_id" instead of just "id".
This means we'd have to do some transformation to be able to cast this to an instance of Listing.
*/
console.log("paginateRaw output (first item):")
console.log(rawListings.items[0])
return []
} |
And they're applied to the raw results instead of the parsed-into- |
Okay this finally makes sense: it's the Background: When we First query: SELECT DISTINCT "distinctAlias"."listings_id" as "ids_listings_id", "distinctAlias"."listings_id"
FROM ( <full_query> ) "distinctAlias"
ORDER BY "distinctAlias"."listings_id" DESC, "listings_id" ASC
LIMIT 4
OFFSET 2 Second query: <full_query>
WHERE "listings"."id" IN ($1, $2, $3, $4)
ORDER BY "listings"."id" DESC
-- PARAMETERS: ["<id1>","<id2>","<id3>","<id4>"] But if we SELECT DISTINCT "distinctAlias"."listings_id" as "ids_listings_id", "distinctAlias"."listings_id", "distinctAlias"."units_max_occupancy", "distinctAlias"."preferences_ordinal"
FROM ( <full_query> ) "distinctAlias"
ORDER BY "distinctAlias"."listings_id" DESC, "distinctAlias"."units_max_occupancy" ASC, "distinctAlias"."preferences_ordinal" ASC, "listings_id" ASC
LIMIT 4
OFFSET 2 (It's looking for distinct instances of I think this gives us two options:
|
This work is close to ready to be reviewed; I just pushed what I have to feature/aeschneider-backend-pagination. What's left to do before sending it off for review:
|
I merged my initial filters branch, so you can probably rebase yours off of |
Thanks to Abbie for getting #133 committed!
I'll fix this and then close this. |
Part of CityOfDetroit/affordable-housing-app#76
We need to add pagination to the listings API so we can don't just have a single page with all listings.
The partner portal currently has pagination for the lists of applications and the early work for listings, so we might be able to use some of that logic. This might be a starting point
This is Done when we have a listings API with pagination.
The text was updated successfully, but these errors were encountered: