Firebase&Filtering按值/键排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Firebase&Filtering按值/键排序相关的知识,希望对你有一定的参考价值。

我在Firebase中有以下结构:

enter image description here

我想只检索属于给定范围内的日期,为此我使用以下return getMealsRefForUser().orderByValue().equalTo("2018-11-17");,其中引用是mealsRefForUser= firebaseDatabase.getReference(MEALS_OF).child(user.getUid());。但是,过滤不会发生。我错过了什么?

编辑:所以,我总是得到/mealsOf/<userId>节点,即使我通过orderByKey().startAt().endAt()限定它,虽然我的目标是获得包含一堆节点的数据快照,其中<year>-<month>-<day>“tag”在给定范围内。

编辑:我想要实现的是将LiveData绑定到这样的查询:

public FirebaseQueryLiveData( Constraints c ) {
    if ( c == null )
        this.query= FirebaseDatabase.getInstance()
            .getReference("/mealsOf")
            .child(FirebaseAuth.getInstance().getCurrentUser().getUid());
    else
        this.query= FirebaseDatabase.getInstance()
            .getReference("/mealsOf")
            .child(FirebaseAuth.getInstance().getCurrentUser().getUid())
            .orderByKey().startAt(c.dayFrom).endAt(c.dayTo);
}

但是这最终给了我整个列表,完全相同 - 不管有什么限制。该类的完整源代码:

// https://firebase.googleblog.com/2017/12/using-android-architecture-components.html
public class FirebaseQueryLiveData extends LiveData<DataSnapshot> {

    private static final String TAG = "FirebaseQueryLiveData";
    private boolean listenerRemovePending= false;
    private final Handler handler= new Handler();

    private final Runnable removeListener= new Runnable() {
        @Override
        public void run() {
            query.removeEventListener(listener);
            listenerRemovePending= false;
        }
    };

    private static final String LOG_TAG= "FirebaseQueryLiveData";

    private final Query query;
    private final InnerValueEventListener listener= new InnerValueEventListener();

    public FirebaseQueryLiveData( Constraints c ) {
        if ( c == null )
            this.query= FirebaseDatabase.getInstance()
                .getReference("/mealsOf")
                .child(FirebaseAuth.getInstance().getCurrentUser().getUid());
        else
            this.query= FirebaseDatabase.getInstance()
                .getReference("/mealsOf")
                .child(FirebaseAuth.getInstance().getCurrentUser().getUid())
                .orderByKey().startAt(c.dayFrom).endAt(c.dayTo);
    }

    public FirebaseQueryLiveData( DatabaseReference ref ) {
        this.query= ref;
    }

    @Override
    protected void onActive() {
        //Log.d(LOG_TAG, "onActive");
        if ( listenerRemovePending )
            handler.removeCallbacks(removeListener);
        else
            query.addValueEventListener(listener);
        listenerRemovePending= false ;
    }

    @Override
    protected void onInactive() {
        //Log.d(LOG_TAG, "onInactive");
        handler.postDelayed(removeListener,2000);
        listenerRemovePending= true ;
        //query.removeEventListener(listener);
    }

    private class InnerValueEventListener implements ValueEventListener {
        @Override
        public void onDataChange( @NonNull DataSnapshot dataSnapshot ) {
            setValue(dataSnapshot);
        }
        @Override
        public void onCancelled( @NonNull DatabaseError databaseError ) {
            Log.e(LOG_TAG, "Can not listen to query " + query,databaseError.toException());
        }
    }
}

我想我知道发生了什么。我的代码中有这篇文章:viewModel= ViewModelProviders.of(this, new CustomViewModelFactory(c)) .get(MealListViewModel.class);

当我提供新的查询约束时,它不会触发。这是否意味着我每次运行应用程序时只能获得一个viewmodelprovider?

编辑:在上面更新的图像中,在日期的meals孩子下我按小时划分 - 例如208PM等。我如何限制我的查询来自两个轴 - 天和小时?在我听到(我必须承认适当的)评论我需要重构我的数据库架构之前,我想知道这是否可行。我们是否需要以下内容?

 return await dbroot.ref(`mealsOf/${userId}`)
        .orderByKey().startAt(dayFrom).endAt(dayTo)
        .orderByChild("meals")
        .startAt(`${hourFrom}:00`).endAt(`${hourTo}:59`)

或者,我应该保留另一个位置,如duplicate/{userId}/{day}/{hour},以启用查询,如

return await dbroot.ref(`duplicate/${userId}`)
            .orderByKey().startAt(dayFrom).endAt(dayTo)
            .orderByKey()
            .startAt(`${hourFrom}:00`).endAt(`${hourTo}:59`)
答案

您不应该使用查询来获取该密钥。如果要返回列表,或者如果您不知道要尝试访问的确切路径,则使用查询。

如您所知uiddate,您可以直接查询对象。

javascript的:

getMealsRefForUser(userId, date) {
  return firebase.database().ref(`/mealsOf/${userId}/${date}`);
}

安卓:

DatabaseReference root = FirebaseDatabase.getInstance().getReference("mealsOf");
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
return root.child(uid).child("2018-11-17");

否则,如果要查询,则应使用startAtendAt方法。

JavaScript的:

getMealsRefForUser(userId, startDate) {
  return firebase.database().ref(`/mealsOf/${userId}`).orderByKey().startAt(startDate);
}

安卓:

return root.orderByKey().startAt("2018-11-17");

以上是关于Firebase&Filtering按值/键排序的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 按值对类数组进行排序

Angular 4 Firebase angularfire 按值对列表进行排序

按值然后键对字典进行排序

使用类提供的排序键按值对字典进行排序

Java 8 流映射到按值排序的键列表

Obj-C,iOS,我如何按值而不是键排序,sortedArrayUsingSelector,目前@selector(compare:)]