evanzhangaus
3/8/2018 - 2:07 AM

pagination

var axios = require('axios');
var firebase = require('firebase').initializeApp({
  "serviceAccount": "./service-account.json",
  "databaseURL": "https://quiver-two.firebaseio.com/"
});

var ref = firebase.app().database().ref();
var peopleRef = ref.child('swapi/people');
// Calling ref.toString() outputs the ref's entire path: https://...firebaseio.com/some/ref/path
var peopleUrl = peopleRef.toString() + '.json?shallow=true'; 
var pageLength = 2;

function getPages(accumulator, cursor) {
  var pages = accumulator || [];
  var query = peopleRef.orderByKey().limitToFirst(pageLength + 1); // limitToFirst starts from the top of the sorted list
  if (cursor) { // If no cursor, start at beginning of collection... otherwise, start at the cursor
    query = query.startAt(cursor);  // Don't forget to overwrite the query variable!
  }

  return query.once('value')
    .then(function (snaps) {
      var page = [];
      var extraRecord;
      snaps.forEach(function (childSnap) {
        page.push({
          id: childSnap.getKey(),
          name: childSnap.val().name
        });
      });
      
      if (page.length > pageLength) {
        extraRecord = page.pop();
        pages.push(page);
        console.log(pages, extraRecord.id);
        return getPages(pages, extraRecord.id);
      } else {
        pages.push(page);
        return Promise.resolve(pages);
      }
    });
};
getPages()
  .then(function (pages) {
    console.log('pages', JSON.stringify(pages));
  });
import admin from 'firebase';
import { last, dropRight } from 'lodash';

admin.initializeApp(functions.config().firebase);

/**
 * Paginate a path on Firebase. Promise.all is used to write current page info and start next query in parallel
 * @param  {String} path Firebase path to paginate
 * @param  {Number} [itemsPerPage=10] Number of items to place in each page
 * @param  {String} startAtKey - Key to start query at (not required for first page)
 * @param  {Number} [currentPage=0] Current page which is being paginated
 * @return {Promise}
 */
const paginate = (path, itemsPerPage = 10, startAtKey, currentPage = 0) => {
  const queryLength = itemsPerPage + 1;
  let query = admin.database().ref(path)
    .orderByKey()
    .limitToFirst(queryLength);

  // start from cursor of last query if it exists
  if (startAtKey) {
    query = query.startAt(startAtKey);
  }

  return query
    .once('value')
    .then((snap) => {
      const list = [];
      snap.forEach((childSnap) => {
        list.push(childSnap.key);
      });
      const nextStartAt = last(list);
      const isLast = list.length < queryLength;
      const promises = [
        admin.database()
          .ref('paginate/results/new')
          .update({
            [currentPage]: {
              list: isLast ? list : dropRight(list),
              nextStartAt,
            },
          }),
      ];
      // add promise to continue process if not last page
      if (!isLast) {
        promises.push(
          paginate(path, itemsPerPage, nextStartAt, currentPage + 1)
        );
      }
      return Promise.all(promises);
    });
};

const pageLength = 10;
paginate('requests/paginate', pageLength);