Показать сообщения в порядке убывания

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

fbl.child('sell').limit(20).on("value", function(fbdata) { 
  // handle data display here
}

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

Ответ 1

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

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

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().limitToLast(20).on('child_added', function(fbdata) {
  console.log(fbdata.exportVal());
})

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

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

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

Ответ 2

Так как 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

Ответ 3

Чтобы увеличить ответ Фрэнка, он также может захватить самые последние записи - даже если вы не потрудились упорядочить их с помощью приоритетов - просто используя 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, естественно, являются изголодателем, независимо от подхода, как только вы попадаете в сотни элементов, поэтому подход к отказу (или решение React.js, которое по сути является дебютом uber) - отличный инструмент для работы.

Ответ 4

На самом деле нет способа, но, похоже, у нас есть 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);

Ответ 5

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

  • Добавить новое длинное поле 'dateInverse'
  • Добавьте новый метод, называемый 'getDateInverse', который только что возвращает: Long.MAX_VALUE - date;
  • Создайте мой запрос с помощью:.orderByChild( "dateInverse" )
  • Presto!: Р

Ответ 6

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

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

этот метод:

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

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

Ответ 7

В 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.

Ответ 8

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

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

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

  • Это позволит получить последние 10 элементов. Возьмите идентификатор последней записи в списке и сохраните для загрузки больше функциональности. Затем преобразуем коллекцию объектов в массив и создаем list.reverse().

  • ЗАГРУЗИТЬ БОЛЬШЕ Функциональность: следующий вызов будет делать две вещи: он получит следующую последовательность элементов списка на основе идентификатора ссылки из первого запроса и даст вам индикатор, если вам нужно отобразить "загрузить больше".

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.
    }
    

Ответ 9

Я использую 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>
        );
    }
}

Ответ 10

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

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;
});

Ответ 11

Чтобы добавить к ответу Дэйва Вавра, я использую отрицательную метку времени, так как моя 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 чтобы он работал еще быстрее

Ответ 12

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

.reverse {
  display: flex;
  flex-direction: column-reverse;
}

Ответ 13

myarray.reverse(); или this.myitems = items.map(item => item).reverse();

Ответ 14

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

query.orderByChild('sell').limitToLast(4).on("value", function(snapshot){
    snapshot.forEach(function (childSnapshot) {
        // PREPEND
    });
});

Ответ 15

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

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

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

Ответ 16

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

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

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

        this.items.push(snapshot);

      });
      **this.items.reverse();**
    },

Ответ 17

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

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

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