Сортировка данных 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

Ответ 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
    })