Как я могу разбивать на страницы в порядке убывания по дочернему значению с помощью firebase?

Скажем, у меня есть некоторые данные следующим образом:

{
    "name": "post #1",
    "votes": 100
},
{
    "name": "post #2",
    "votes": 10000
},
{
    "name": "post #3",
    "votes": 750
}

И так далее.

Данные в firebase не упорядочены по голосам, очевидно, они упорядочиваются по ключу.

Я хотел бы иметь возможность разбивать эти данные на количество голосов в порядке убывания.

Думаю, мне нужно было сделать что-то вроде:

ref.orderByChild('votes')
    .startAt(someValue)
    .limitToFirst(someOtherValue)
    .once('value', function(snapshot) {
        resolve(snapshot);
    });

Или, может быть, мне нужно будет использовать limitToLast и endAt?

Разбиение страницы на key довольно просто, но это меня бросает.

Обновление (2017-10-16): Firebase недавно объявила Firestore - их полностью управляемый NoSQL который должен облегчить выполнение более сложных запросов. Там могут быть некоторые варианты использования, где можно использовать базу данных Realtime, которую они всегда предоставляли. Если вы один из тех людей, этот вопрос все равно должен применяться.

Ответ 1

Я разместил этот вопрос после долгого дня кодирования, и мой мозг был месиво.

Сегодня утром я сделал еще одну попытку, и, как это часто бывает, смог найти решение довольно быстро.

Решение:

Чтобы разбивать данные, нам нужна возможность произвольно вытащить отсортированные данные из середины списка. Вы можете сделать это, используя следующие функции, предоставляемые API Firebase:

startAt

endAt

limitToFirst

limitToLast

Более подробную информацию можно найти здесь.

В моем случае, так как мне нужны мои данные в порядке убывания, я буду использовать endAt и limitToLast.

Предполагая, что каждая из моих страниц будет иметь пять. Я бы написал свой первый запрос следующим образом:

ref.orderByChild('votes')
    .limitToLast(5)
    .once('value', function(snapshot) {
      console.log('Snap: ', snapshot.val());
    });

Это получает 5 элементов с наивысшим числом голосов.

Чтобы получить следующую страницу, нам нужно будет сохранить две части данных из результатов нашего последнего запроса. Нам нужно сохранить количество голосов и ключ для элемента с наименьшим количеством голосов. То есть последний пункт в нашем списке.

Используя эти данные, наш следующий запрос и все последующие запросы выглядят следующим образом:

ref.orderByChild('votes')
    .endAt(previousVoteCount, previousKey)
    .limitToLast(5)
    .once('value', function(snapshot) {
      console.log('Snap: ', snapshot.val());
    });

В этом вопросе вы заметите, что я добавил endAt. Это получает следующие 5 предметов с наибольшим количеством голосов, начиная с последнего в предыдущем списке. Мы должны включить ключ для последнего элемента в предыдущем списке, чтобы, если есть несколько элементов с одинаковым количеством голосов, он вернет список, начинающийся с правильного элемента, а не первый, который он найдет с этим номером голосов, которые могут находиться где-то посреди списка, полученного из исходного запроса.

Что это!