Показать сообщения в порядке убывания
Я пытаюсь проверить 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) вы получите то, что вам нужно.