Сортировка данных Firebase Desc в Android
Я храню данные в хранилище Firebase.
Объект Comment
с атрибутом timestamp
. Когда я отправляю данные с устройства в Firebase, я заполняю timestamp
currentTime и сохраняю в типе данных long
.
Когда я получаю данные с firebaseRef.orderByChild("timestamp").limitToLast(15)
, результат не сортируется так, как я ожидал.
Я даже играл с правилами и без результата:
{
"rules": {
".read": true,
".write": true,
".indexOn": "streetrate",
"streetrate": {
".indexOn": ".value"
}
}
}
Я попытался сохранить timestamp
в типе данных String
, та же проблема.
Ответы
Ответ 1
Firebase может упорядочить элементы в порядке возрастания по заданному свойству и затем возвращает либо первые N элементов (limitToFirst()
), либо последние N элементов (limitToLast()
). Невозможно указать, что вы хотите, чтобы элементы были в порядке убывания.
Существует два варианта получения желаемого поведения:
-
Используйте запрос Firebase для получения правильных данных, затем повторно заказывайте его на стороне клиента
-
Добавить поле, которое имеет нисходящее значение для данных
Для последнего подхода обычно имеет инвертированную временную метку.
-1 * new Date().getTime();
Ответ 2
одно хорошее решение, которое я нахожу, если вы используете просмотр recycler для визуализации этих данных...
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
// And set it to RecyclerView
mRecyclerView.setLayoutManager(mLayoutManager);
он отменит обработку данных...
private static class ChatMessageViewHolder extends RecyclerView.ViewHolder {
TextView messageText;
TextView nameText;
public ChatMessageViewHolder(View itemView) {
super(itemView);
nameText = (TextView)itemView.findViewById(android.R.id.text1);
messageText = (TextView) itemView.findViewById(android.R.id.text2);
}
}
FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder> adapter;
ref = new Firebase("https://<yourapp>.firebaseio.com");
RecyclerView recycler = (RecyclerView)
findViewById(R.id.messages_recycler);
recycler.setHasFixedSize(true);
//////////////////////////////////////////////////////////
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
recycler.setLayoutManager(mLayoutManager);
/////////////////////////////////////////////////////////
adapter = new FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder>(ChatMessage.class, android.R.layout.two_line_list_item, ChatMessageViewHolder.class, mRef) {
public void populateViewHolder(ChatMessageViewHolder chatMessageViewHolder, ChatMessage chatMessage) {
chatMessageViewHolder.nameText.setText(chatMessage.getName());
chatMessageViewHolder.messageText.setText(chatMessage.getMessage());
}
};
recycler.setAdapter(mAdapter);
Ответ 3
Я не вижу возможности изменить данные. Но один грубый способ - получить данные.
List<ModelClass> mList=new ArrayList();
public void onDataChange(DataSnapshot dataSnapshot)
{
mList.clear();
for(DataSnapshot children: dataSnapshot.getChildren()){
ModelClass modelClass=children.getValue(ModelClass.class);
mList.add(modelClass);
}
Collections.reverse(mList);
Adapter.notifyDataSetChanged();
}
Ответ 4
Я решил проблему, расширив FirebaseListAdapter и переопределив метод getItem:
public abstract class ReverseFirebaseListAdapter<T> extends FirebaseListAdapter<T> {
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, Query ref) {
super(activity, modelClass, modelLayout, ref);
}
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, DatabaseReference ref) {
super(activity, modelClass, modelLayout, ref);
}
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
}
Ответ 5
Подход @Monet_z_Polski, основанный на
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
имеет странный эффект при автоматическом обновлении FirebaseRecyclerView (PopulationViewHolder не запускается в реальном времени). Таким образом, лучший вариант использовать отрицательный ключ для индексации данных.
Ответ 6
Сортировка на стороне клиента проста и не требует больше системных ресурсов.
В каждом снимке данных есть поле previousChildkey. Если вы хотите отсортировать сортировку, представьте, что previousChildkey является nextChildKey.
Вот мой пример:
class LessonFirebaseArray<ObjectModel>{
private ArrayList<ObjectModel> mItems;
...
public LessonFirebaseArray() {
mItems = new ArrayList<>();
}
public int addItem(ObjectModel item, boolean isReverse){
int index;
if (item.getPreviousChildKey() != null) {
index = getIndexForKey(item.getPreviousChildKey());
if (index < 0) {
index = mItems.size();
}else if(index>0 && !isReverse) {
index = index + 1;
}
}else{
index = mItems.size();
}
mItems.add(index, item);
notifyInsertedListeners(index);
return index;
}
private int getIndexForKey(String key) {
int index = 0;
for (ObjectModel snapshot : mItems) {
if (snapshot.getKey().equals(key)) {
return index;
} else {
index++;
}
}
return -1;
}
private void notifyInsertedListeners(int index) {
if (mListener != null) {
mListener.onInserted(index);
}
}
}
Ответ 7
Сортировка дочерних элементов по TIMESTAMP может быть выполнена с помощью android.support.v7.util.SortedList
class post{
private Object time;
public Object getTime() {
return time;
}
public void setTime(Object time) {
this.time = time;
}
...//rest code}
SortedList<post> data;
data = new SortedList<post>(post.class, new SortedList.Callback<post>() {
@Override
public int compare(post o1, post o2) {
Long o1l = Long.parseLong(o1.getTime().toString());
Long o2l = Long.parseLong(o2.getTime().toString());
return o2l.compareTo(o1l);
}......//rest code
ref.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mSwipeRefreshLayout.setRefreshing(true);
post p=dataSnapshot.getValue(post.class);
data.add(p);
}...// rest code
android.support.v7.util.SortedList
также может использоваться с RecyclerView
Ответ 8
Если вы делаете это в Интернете, вы можете поместить значения в массив, а затем распечатать сохраненные значения в обратном порядке.
var a=[]; //declaring an array a.
var num=snapshot.numChildren(); //storing number of children in var num.
a.push(snapshot.val()); // pushing data in the array.
if (a.length==num){ //checking if length of array is same as number of children.
a.reverse(); //reversing the array elements.
for(i=0; i<num; i++){
a[i].name;//this will sort the data in descending order.
}
}
Ответ 9
добавить столбец, а именно отметку времени со значениями (-1*System.currentTimeMillis())
и при получении данных использовать orderByChild("timestamp").limitToFirst(15)
или orderByChild("timestamp").limitToLast(15)
согласно вашему требованию.
Это умный способ получить данные в отсортированном виде, так как Firebase не имеет правил для убывающего порядка.
Ответ 10
Это очень просто: используйте -1, - 2, -3 и т.д. Для хранения данных в базе данных firebase. Теперь данные будут отображаться в обратном порядке в recyclerView.
-3
-2
-1
Ответ 11
Я обнаружил, что текущая версия Firebase поддерживает сортировку по убыванию:
citiesRef.orderBy("name", "desc").limit(3)
https://firebase.google.com/docs/firestore/query-data/order-limit-data
Надеюсь, это поможет
Ответ 12
Swift 3:
let query = firebase.child(YourQueryPath).queryOrdered(byChild: YourQueryChild).queryLimited(toLast: YourLimit)
query.observeSingleEvent(of: .value, with: { (snapshot) in
// Reverse order here to get top **YourLimit** results in descending order
})