Reputation: 1249
I have the following structure in Firebase:
I would like to retrieve only the dates falling within a given range, and for that I was using the following return getMealsRefForUser().orderByValue().equalTo("2018-11-17");
, where the reference is mealsRefForUser= firebaseDatabase.getReference(MEALS_OF).child(user.getUid());
.
However, the filtering does not happen. What am I missing?
EDIT: So, I am always getting the /mealsOf/<userId>
node, even if I qualify it by orderByKey().startAt().endAt()
, although my aim is to get a data snapshot that contains a bunch of nodes whose <year>-<month>-<day>
"tag" is within the given range.
EDIT: What I am trying to achieve is to bind LiveData
to a query like this:
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);
}
But this ends up giving me the entire list, all the same -- regardless of the constraints. The whole source code of the class:
// 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());
}
}
}
I think I know what is happening. I have this piece in my code:
viewModel= ViewModelProviders.of(this, new CustomViewModelFactory(c))
.get(MealListViewModel.class);
It is not firing when I supply new query constraints. Does it mean that I can get only one viewmodelprovider per run of my application?
EDIT: In the above updated image, under the meals
child of a date I have the division by hours -- e.g. 20
being 8PM
etc. How would I restrict my query from both axes -- days and hours?
Before I hear (I must admit appropriate) comments that I need to restructure my database schema, I would like to know if that is possible.
Would we need something along the lines of the following?
return await dbroot.ref(`mealsOf/${userId}`)
.orderByKey().startAt(dayFrom).endAt(dayTo)
.orderByChild("meals")
.startAt(`${hourFrom}:00`).endAt(`${hourTo}:59`)
Or alternatively, should I keep another location such as duplicate/{userId}/{day}/{hour}
to enable queries such as
return await dbroot.ref(`duplicate/${userId}`)
.orderByKey().startAt(dayFrom).endAt(dayTo)
.orderByKey()
.startAt(`${hourFrom}:00`).endAt(`${hourTo}:59`)
Upvotes: 0
Views: 671
Reputation: 2688
You shouldn't be using a query to grab that key. Queries are used if you want a list returned, or if you don't know the exact path you're trying to reach.
As you know the uid
and the date
you can query the object directly.
JavaScript:
getMealsRefForUser(userId, date) {
return firebase.database().ref(`/mealsOf/${userId}/${date}`);
}
Android:
DatabaseReference root = FirebaseDatabase.getInstance().getReference("mealsOf");
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
return root.child(uid).child("2018-11-17");
Otherwise if you want to query you should use the startAt
or endAt
methods.
JavaScript:
getMealsRefForUser(userId, startDate) {
return firebase.database().ref(`/mealsOf/${userId}`).orderByKey().startAt(startDate);
}
Android:
return root.orderByKey().startAt("2018-11-17");
Upvotes: 2