0
votes

I'm trying to do a pagination where the user can see each button's page number in the UI. I'm using Firestore and Buefy for this project.

My problem is that Firestore is returning wrong queries for this case. Sometimes (depending the page that the users clicks on) It works but sometimes don't (It returns the same data of the before page button). It's really messy I don't understand what's going on. I'll show you the code:

Vue component: (pay attention on the onPageChange method)

<template>
    <div>
        <b-table
            :data="displayData"
            :columns="table.columns"
            hoverable
            scrollable
            :loading="isLoading"
            paginated
            backend-pagination
            :total="table.total"
            :per-page="table.perPage"
            @page-change="onPageChange">

        </b-table>
    </div>
</template>

<script>
import { fetchBarriosWithLimit, getTotalDocumentBarrios, nextBarrios } from '../../../../firebase/firestore/Barrios/index.js'
import moment from 'moment'
const BARRIOS_PER_PAGE = 5
    export default {
        data() {
            return {
                table: {
                    data: [],
                    columns: [
                        {
                            field: 'name',
                            label: 'Nombre'
                        },
                        {
                            field: 'dateAddedFormatted',
                            label: 'Fecha aƱadido'
                        },
                        {
                            field: 'totalStreets',
                            label: 'Total de calles'
                        }
                    ],
                    perPage: BARRIOS_PER_PAGE,
                    total: 0
                },
                isLoading: false,
                lastPageChange: 1
            }
        },
        methods: {
            onPageChange(pageNumber) {
                // This is important. this method gets fired each time a user clicks a new page. I page number that the user clicks.
                this.isLoading = true
                if(pageNumber === 1) {
                    console.log('show first 5...')
                    return;
                }
                const totalPages = Math.ceil(this.table.total / this.table.perPage)
                if(pageNumber === totalPages) {
                    console.log('show last 5...')
                    return;
                }

                /* Here a calculate the next starting point */
                const startAfter = (pageNumber - 1) * this.table.perPage
                nextBarrios(this.table.perPage, startAfter)
                    .then((querySnap) => {
                        this.table.data = []
                        this.buildBarrios(querySnap)
                        console.log('Start after: ', startAfter)
                    })
                    .catch((err) => {
                        console.err(err)
                    })
                    .finally(() => {
                        this.isLoading = false
                    })
                
            },
            buildBarrios(querySnap) {
                querySnap.docs.forEach((docSnap) => {
                        this.table.data.push({
                        id: docSnap.id,
                        ...docSnap.data(),
                        docSnapshot: docSnap
                    })
                });
            }
        },
        computed: {
            displayData() {
                let data = []
                this.table.data.map((barrioBuieldedObj) => {
                    barrioBuieldedObj.dateAddedFormatted = moment(Number(barrioBuieldedObj.dateAdded)).format("DD/MM/YYYY")
                    barrioBuieldedObj.totalStreets ? true : barrioBuieldedObj.totalStreets = 0;
                    data.push(barrioBuieldedObj)
                });
                return data;
            }
        },
        mounted() {
            // obtener primer paginacion y total de documentos.
            this.isLoading = true
            getTotalDocumentBarrios()
                .then((docSnap) => {
                    if(!docSnap.exists || !docSnap.data().totalBarrios) {
                        // mostrar mensaje que no hay barrios...
                        console.log('No hay barrios agregados...')
                        this.table.total = 0
                        return;
                    }
                    const totalBarrios = docSnap.data().totalBarrios
                    this.table.total = totalBarrios
                    if(totalBarrios <= BARRIOS_PER_PAGE) {
                        return fetchBarriosWithLimit(totalBarrios)
                    } else {
                        return fetchBarriosWithLimit(BARRIOS_PER_PAGE)
                    }
                    
                })
                .then((querySnap) => {
                    if(querySnap.empty) {
                        // ningun doc. mostrar mensaje q no hay barrios agregados...
                        return;
                    }
                    this.buildBarrios(querySnap)
                })
                .catch((err) => {
                    console.error(err)
                })
                .finally(() => {
                    this.isLoading = false
                })
        }
    }
</script>

<style lang="scss" scoped>

</style>

The nextBarrios function:

function nextBarrios(limitNum, startAtNum) {

    const query = db.collection('Barrios')
                    .orderBy('dateAdded')
                    .startAfter(startAtNum)
                    .limit(limitNum)
    return query.get()
}

db is the result object of calling firebase.firestore(). Can I tell a query to start at a certain number where number is the index position of the document within a collection? If not, How could I approach this problem?

Thank you!

1

1 Answers

1
votes

Firestore doesn't support offset or index based pagination. It's also not possible to tell how many documents the entire query would return without actually reading them all. So, unfortunately, what you're trying to do isn't possible with Firestore.

It seems also that you're misunderstanding how the pagination APIs actually work. startAfter doesn't take an index - it takes either a DocumentSnapshot of the last document in the prior page, or a value of the ordered field that you used to sort the query, again, the last value you saw in the prior page. You are basically going to use the API to tell it where to start in the next page of results based on what you found in the last page. That's what the documentation means when it says you are working with a "query cursor".