Как получить данные из Firebase в порядке убывания с помощью orderByChild [duplicate]

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
35
задан JasonMArcher 10 September 2014 в 22:36
поделиться

18 ответов

Firebase: как отобразить поток элементов в обратном порядке с лимитом для каждого запроса и индикатором кнопки «загрузить больше».

  • Это позволит получить последние 10 элементов список

FBRef.child ("childName") .limitToLast (loadMoreLimit) // loadMoreLimit = 10, например

  • Это будет последнее 10 элементов , Возьмите идентификатор последней записи в списке и сохраните для загрузки больше функциональности. Затем преобразуем коллекцию объектов в массив и создаем list.reverse ().
  • LOAD MORE Функциональность: следующий вызов будет делать две вещи: он получит следующую последовательность элементов списка на основе идентификатора ссылки из первого запроса и даст вам индикатор, если вам нужно отобразить «load» больше ".

this.FBRef .child ("childName") .endAt (null, lastThreadId) // Получить это с предыдущего шага .limitToLast (loadMoreLimit + 2)

  • Вам нужно будет удалить первый и последний элемент этой коллекции объектов. Первый элемент - ссылка для получения этого списка. Последний элемент является индикатором кнопки «Показать больше».
  • У меня есть куча другой логики, которая будет держать все в чистоте. Вам нужно будет добавить этот код только для большей функциональности загрузки.
      list = snapObjectAsArray;  // The list is an array from snapObject
      lastItemId = key; // get the first key of the list
    
      if (list.length < loadMoreLimit+1) {
        lastItemId = false; 
      }
      if (list.length > loadMoreLimit+1) {
        list.pop();
      }
      if (list.length > loadMoreLimit) {
        list.shift();
      }
      // Return the list.reverse() and lastItemId 
      // If lastItemId is an ID, it will be used for the next reference and a flag to show the "load more" button.
    }
    
2
ответ дан Andrew Axelrod 18 August 2018 в 18:49
поделиться

Я сделал это с помощью preend.

query.orderByChild('sell').limitToLast(4).on("value", function(snapshot){
    snapshot.forEach(function (childSnapshot) {
        // PREPEND
    });
});
0
ответ дан angel enanod 18 August 2018 в 18:49
поделиться

Кто-то указал, что есть два способа сделать это:

  1. Манипулировать клиентскую сторону данных
  2. Сделать запрос, который будет упорядочивать данные

Самый простой способ, который я нашел для этого, - использовать параметр 1, но через LinkedList. Я просто добавляю каждый из объектов к передней части стека. Он достаточно гибкий, чтобы позволить использовать список в файлах ListView или RecyclerView. Таким образом, несмотря на то, что они приходят по порядку от старости к новейшим, вы все равно можете просматривать или загружать самые новые до самых старых.

0
ответ дан BlackHatSamurai 18 August 2018 в 18:49
поделиться

У меня тоже была эта проблема, я нашел очень простое решение, которое в любом случае не включало манипулирование данными. Если вы разорёте результат в DOM, в каком-то списке. Вы можете использовать flexbox и настроить класс для изменения элементов в своем контейнере.

.reverse {
  display: flex;
  flex-direction: column-reverse;
}
1
ответ дан Darren 18 August 2018 в 18:49
поделиться

Есть лучший способ. Вы должны заказать минус-метку сервера. Как получить отрицательную отметку времени сервера даже в автономном режиме? Это помогает скрытое поле. Связанный фрагмент документа:

var offsetRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/.info/serverTimeOffset");
  offsetRef.on("value", function(snap) {
  var offset = snap.val();
  var estimatedServerTimeMs = new Date().getTime() + offset;
});
1
ответ дан David Vávra 18 August 2018 в 18:49
поделиться

В Android существует способ фактического изменения данных в Arraylist объектов через адаптер. В моем случае я не мог использовать LayoutManager для изменения результатов в порядке убывания, так как я использовал горизонтальный Recyclerview для отображения данных. Установка следующих параметров в recyclerview испортила мой опыт работы с интерфейсом:

llManager.setReverseLayout(true);
llManager.setStackFromEnd(true);

Единственный рабочий путь, который я нашел вокруг этого, был через метод BindViewHolder адаптера RecyclerView:

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
    final SuperPost superPost = superList.get(getItemCount() - position - 1);
}

Надеюсь, этот ответ поможет всем разработчикам, которые борются с этой проблемой в Firebase.

2
ответ дан dev.mi 18 August 2018 в 18:49
поделиться

Поскольку этот ответ был написан, Firebase добавила функцию, которая позволяет упорядочивать любой дочерний элемент или значение. Таким образом, теперь есть четыре способа заказа данных: по ключу, по значению, по приоритету или по значению любого именованного дочернего элемента. [Gg]

Основные подходы остаются неизменными, хотя:

] 1. Добавьте дочернее свойство с инвертированной меткой времени, а затем закажите это.

2. Прочитайте их в порядке возрастания, а затем инвертируйте их на клиенте.

Firebase поддерживает извлечение дочерних узлов коллекции двумя способами:

  • по имени
  • по приоритету

То, что вы получаете сейчас, называется по имени, что бывает хронологическим. Это не совпадение кстати: когда вы push элемент в коллекцию, имя создается, чтобы гарантировать, что дети упорядочены таким образом. Чтобы процитировать документацию Firebase для push :

Уникальное имя, сгенерированное push (), имеет префикс с меткой времени, созданной клиентом, так что результирующий список будет хронологически отсортированы.

В руководстве Firebase по упорядоченным данным есть это сказать по теме:

Как данные упорядочены

По умолчанию дети в узле Firebase сортируются лексикографически по имени. Использование push() может генерировать дочерние имена, которые, естественно, сортируются в хронологическом порядке, но многие приложения требуют, чтобы их данные сортировались другими способами. Firebase позволяет разработчикам указывать порядок элементов в списке, указав собственный приоритет для каждого элемента.

Самый простой способ получить нужное поведение - также указать всегда убывающий приоритет, когда вы добавите элемент:

var ref = new Firebase('https://your.firebaseio.com/sell');
var item = ref.push();
item.setWithPriority(yourObject, 0 - Date.now());

Обновить

Вам также придется искать детей по-другому:

fbl.child('sell').startAt().limit(20).on('child_added', function(fbdata) {
  console.log(fbdata.exportVal());
})

В моем тесте с использованием on('child_added' гарантирует, что последние несколько детей добавлены в обратном хронологическом порядке. С другой стороны, с помощью on('value' возвращает их в порядке их имени.

Обязательно прочитайте раздел «Чтение упорядоченных данных» , в котором объясняется использование child_* события для извлечения (упорядоченных) детей.

Бит для демонстрации этого: http://jsbin.com/nonawe/3/watch?js,console

40
ответ дан Frank van Puffelen 18 August 2018 в 18:49
поделиться
  • 1
    Пробовал это, но я все еще получаю данные, возвращенные в том порядке, в котором он был введен. – user2912591 1 September 2014 в 23:13
  • 2
    Да, у меня была ошибка. Вы хотите иметь обратную хронологию, поэтому должны обеспечить, чтобы значения становились меньше с течением времени. Я изменил код, чтобы показать один из способов сделать это. Но я надеюсь, что мое объяснение позволит вам придумать способ, который лучше подходит для вашего сценария. – Frank van Puffelen 1 September 2014 в 23:18
  • 3
    Я считаю, что для простых случаев использования (для списков, измеренных в сотнях) endAt (). Limit (x) должен предоставить вам самые последние элементы в списке без необходимости устанавливать приоритет. Затем их можно было бы поменять местами по низкой цене. Очевидно, что ответ Фрэнка - гораздо более тщательное и масштабируемое решение. – Kato 2 September 2014 в 20:05
  • 4
    @ Kato: Я попытался изменить их, но боролся. Можете ли вы поделиться фрагментом (или отдельным ответом) о том, как это сделать? (потому что это действительно было бы намного проще) – Frank van Puffelen 2 September 2014 в 20:22
  • 5
    Поделился фрагментом в качестве дополнительного ответа. – Kato 3 September 2014 в 18:38

На самом деле нет способа, но, похоже, у нас есть recyclerview, у нас может быть это

 query=mCommentsReference.orderByChild("date_added");
        query.keepSynced(true);

        // Initialize Views
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
        mManager = new LinearLayoutManager(getContext());
//        mManager.setReverseLayout(false);
        mManager.setReverseLayout(true);
        mManager.setStackFromEnd(true);

        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(mManager);
3
ответ дан Goodlife 18 August 2018 в 18:49
поделиться

Чтобы увеличить ответ Фрэнка, можно также захватить самые последние записи - даже если вы не потрудились упорядочить их с использованием приоритетов - просто используя endAt().limit(x), как это demo :

var fb = new Firebase(URL);

// listen for all changes and update
fb.endAt().limit(100).on('value', update);

// print the output of our array
function update(snap) {
   var list = [];
    snap.forEach(function(ss) {
       var data = ss.val();
       data['.priority'] = ss.getPriority();
       data['.name'] = ss.name();
       list.unshift(data); 
    });
   // print/process the results...
}

Обратите внимание, что это довольно показательно даже до тысячи записей (при условии, что полезная нагрузка мала).

Эта грубая сила также может быть оптимизирована для работы с большими данными или большими записями, выполняя такие функции, как мониторинг child_added / child_removed / child_moved вместо value и используя debounce для применения обновлений DOM навалом, а не отдельно.

Обновления DOM, естественно, являются стервой независимо от подхода , как только вы попадаете в сотни элементов, так что подход debounce (или решение React.js, который по сути является debub uber) - отличный инструмент для работы.

7
ответ дан Kato 18 August 2018 в 18:49
поделиться

Чтобы добавить к ответу Дэйва Вавры, я использую отрицательную метку времени, так как мой sort_key нравится так

Установка

const timestamp = new Date().getTime();
const data = {
  name: 'John Doe',
  city: 'New York',
  sort_key: timestamp * -1 // Gets the negative value of the timestamp
}

Получение

const ref = firebase.database().ref('business-images').child(id);
const query = ref.orderByChild('sort_key');
return $firebaseArray(query); // AngularFire function

Это позволяет извлекать все объекты от самых новых до самых старых. Вы также можете $indexOn sortKey сделать его еще быстрее

1
ответ дан Kurai Bankusu 18 August 2018 в 18:49
поделиться
  • 1
    Почему это отрицательно: timestamp * 1? Является ли этот javascript конкретным? – Jemshit Iskenderov 7 February 2018 в 14:21
  • 2
    @JemshitIskenderov моя ошибка, я хотел написать timestamp * -1. Это приведет к отрицательному значению – Kurai Bankusu 7 February 2018 в 15:27

Поскольку firebase 2.0.x вы можете использовать limitLast() для достижения этого:

fbl.child('sell').orderByValue().limitLast(20).on("value", function(fbdataSnapshot) { 
  // fbdataSnapshot is returned in the ascending order
  // you will still need to order these 20 items in
  // in a descending order
}

Вот ссылка на объявление: Дополнительные возможности запросов в Firebase

10
ответ дан Maksymilian Majer 18 August 2018 в 18:49
поделиться
  • 1
    Вместо append вы можете использовать prepend для добавления элементов в обратном порядке. – Mygod 14 July 2015 в 01:52
  • 2
    в дополнение к limitLast (n) нам нужно отсортировать данные. В случае углового это можно сделать, используя фильтр orderBy в порядке убывания, основанный на поле даты как элемент ng-repeat = "в ctrl.items | OrderBy: '- временная метка' & Quot; -timestamp отменяет порядок – ozkary 13 February 2016 в 21:02
  • 3
    Mygod thanks preend - именно то, что я хотел в моем случае. Сохраняет выполнение дополнительной сортировки + добавление. – shell 2 January 2017 в 00:49

Вы ищете limitTolast (Int x). Это даст вам последние «x» более высокие элементы вашей базы данных (они находятся в порядке возрастания), но они являются «x» более высокими элементами

, если вы получили в своей базе данных {10,300,150,240,2,24,220}

этот метод:

myFirebaseRef.orderByChild("highScore").limitToLast(4)

выведет вас: {150,220,240,300}

3
ответ дан Manuel Mena Rodríguez 18 August 2018 в 18:49
поделиться

Вы можете добавить столбец с именем orderColumn, где вы сэкономите время, когда

Long refrenceTime = "large future time"; Long currentTime = "currentTime"; Long order = refrenceTime - currentTime;

теперь сохраняете длинный порядок в столбце с именем orderColumn и когда вы извлекаете данные в качестве orderBy (orderColumn) вы получите то, что вам нужно.

0
ответ дан Parvesh Monu 18 August 2018 в 18:49
поделиться

просто используйте reverse() в массиве, предположим, что если вы сохраняете значения в массиве items[], тогда выполните this.items.reverse()

 ref.subscribe(snapshots => {
       this.loading.dismiss();

      this.items = [];
      snapshots.forEach(snapshot => {

        this.items.push(snapshot);

      });
      **this.items.reverse();**
    },
0
ответ дан pirs 18 August 2018 в 18:49
поделиться

Я использую ReactFire для легкой интеграции Firebase.

В основном, это помогает мне хранить данные в состоянии компонента, как array. Тогда все, что мне нужно использовать, это функция reverse() ( подробнее )

Вот как я это достигаю:

import React, { Component, PropTypes } from 'react';
import ReactMixin from 'react-mixin';
import ReactFireMixin from 'reactfire';

import Firebase from '../../../utils/firebaseUtils'; // Firebase.initializeApp(config);

@ReactMixin.decorate(ReactFireMixin)
export default class Add extends Component {
    constructor(args) {
        super(args);

        this.state = {
            articles: []
        };
    }

    componentWillMount() {
        let ref = Firebase.database().ref('articles').orderByChild('insertDate').limitToLast(10);
        this.bindAsArray(ref, 'articles'); // bind retrieved data to this.state.articles
    }

    render() {
        return (
            <div>
                {
                    this.state.articles.reverse().map(function(article) {
                        return <div>{article.title}</div>
                    })
                }
            </div>
        );
    }
}
2
ответ дан pistou 18 August 2018 в 18:49
поделиться

У меня есть переменная date (long) и вы хотите сохранить новейшие элементы в верхней части списка. Итак, я сделал это:

  • Добавить новое длинное поле 'dateInverse'
  • Добавить новый метод, называемый 'getDateInverse', который только что возвращает: Long.MAX_VALUE - date;
  • Создайте мой запрос с помощью: .orderByChild ("dateInverse")
  • Presto! : p
3
ответ дан Spoetnic 18 August 2018 в 18:49
поделиться
  • 1
    Обратите внимание, что это не работает для существующих элементов, если вы не установите их значения еще раз. – Spoetnic 7 March 2016 в 18:24
  • 2
    Вы можете также разместить знак минуса до даты. – Yaroslav 8 August 2017 в 09:12
0
ответ дан PHILL BOOTH 7 September 2018 в 03:06
поделиться
0
ответ дан PHILL BOOTH 30 October 2018 в 07:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: