Search code examples
javascriptfirebasefirebase-realtime-databaseangularfire2

Firebase filter with pagination


I'm doing an opensource Yelp with Firebase + Angular.

My database:

    {
      "reviews" : {
        "-L0f3Bdjk9aVFtVZYteC" : {
          "comment" : "my comment",
          "ownerID" : "Kug2pR1z3LMcZbusqfyNPCqlyHI2",
          "ownerName" : "MyName",
          "rating" : 2,
          "storeID" : "-L0e8Ua03XFG9k0zPmz-"
        },
        "-L0f7eUGqenqAPC1liYj" : {
          "comment" : "me second comment",
          "ownerID" : "Kug2pR1z3LMcZbusqfyNPCqlyHI2",
          "ownerName" : "MyName",
          "rating" : 3,
          "storeID" : "-L0e8Ua03XFG9k0zPmz-"
        },    
      },
      "stores" : {
        "-L0e8Ua03XFG9k0zPmz-" : {      
          "description" : "My good Store",      
          "name" : "GoodStore",
          "ownerID" : "39UApyo0HIXmKPrTOi8D0nWLi6n2",      
          "tags" : [ "good", "health", "cheap" ],
        }
      },
      "users" : {
        "39UApyo0HIXmKPrTOi8D0nWLi6n2" : {
          "name" : "First User"
        },
        "Kug2pR1z3LMcZbusqfyNPCqlyHI2" : {
          "name" : "MyName",
          "reviews" : {
            "-L0f3Bdjk9aVFtVZYteC" : true,
            "-L0f7eUGqenqAPC1liYj" : true
          }
        }
      }
    }

I use this code below to get all store's reviews (using AngularFire2)

    getReviews(storeID: string){
        return this.db.list('/reviews', ref => { 
            return ref.orderByChild('storeID').equalTo(storeID);
        });
    }

Now, I want to make a server-side review pagination, but I think I cannot do it with this database structure. Am I right? Tried:

    getReviews(storeID: string){
        return this.db.list('/reviews', ref => { 
            return ref.orderByChild('storeID').equalTo(storeID).limitToLast(10) //How to make pagination without retrive all data?
        });
    }

I thought that I could put all reviews inside stores, but (i) I don't want to retrieve all reviews at once when someone ask for a store and (ii) my review has a username, so I want to make it easy to change it (that why I have a denormalized table)


Solution

  • For the second page you need to know two things:

    1. the store ID that you want to filter on
    2. the key of the review you want to start at

    You already have the store ID, so that's easy. As the key to start at, well use the key of the last item on the previous page, and then just request one item extra. Then finally, you'll need to use start() (and possibly endAt() for this:

    return this.db.list('/reviews', ref => { 
        return ref.orderByChild('storeID')
                  .startAt(storeID, lastKeyOnPreviousPage)
                  .limitToLast(11)
    });