Reputation: 37
I was trying to search through the Firebase database from my material search dialog. I was successful in doing that but the problem is that I can search only through titles(my database contains title and descriptions too), although I tried quite a many things nothing worked for me.
At some point, I succeeded by making another search function for searching descriptions but then it made the searched results for titles to misbehave.
I am attaching the code below can, please have a look at it and let me know if there is anything that I can do to search through both titles and descriptions.
Declarations and code(I have skipped the unrequired parts from the activity code)
materialSearchBar = homeView.findViewById(R.id.searchBar);
materialSearchBar.setHint("Search Ad");
loadSuggest();
materialSearchBar.setLastSuggestions(suggestList);
materialSearchBar.setCardViewElevation(10);
materialSearchBar.addTextChangeListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
List<String> sugest = new ArrayList<String>();
for (String search : suggestList) {
if (search.toLowerCase().contains(materialSearchBar.getText().toLowerCase()))
sugest.add(search);
}
materialSearchBar.setLastSuggestions(sugest);
}
@Override
public void afterTextChanged(Editable editable) {
}
});
materialSearchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
@Override
public void onSearchStateChanged(boolean enabled) {
if (!enabled)
mallUsers.setAdapter(firebaseRecyclerAdapter);
}
@Override
public void onSearchConfirmed(CharSequence text) {
startSearch(text);
}
@Override
public void onButtonClicked(int buttonCode) {
}
});
// start search and load suggestions methods
private void startSearch(CharSequence text) {
String searchText = text.toString();
Query query1 = mDatabase1.orderByChild("title").startAt(searchText).endAt(searchText + "\uf8ff");
Query query2 = mDatabase1.orderByChild("description").startAt(searchText).endAt(searchText + "\uf8ff");
FirebaseRecyclerOptions<Ad> firebaseRecyclerOptions2 = new FirebaseRecyclerOptions
.Builder<Ad>()
.setQuery(query1, Ad.class)
.build();
searchAdapter = new FirebaseRecyclerAdapter<Ad, UsersViewHolder1>(firebaseRecyclerOptions2) {
@Override
protected void onBindViewHolder(@NonNull UsersViewHolder1 holder, int position, @NonNull Ad ad1) {
holder.setTitle(ad1.getTitle());
holder.setPrice(ad1.getPrice());
holder.setCategory(ad1.getCategory());
holder.setImage(ad1.getImage(), getContext());
holder.setTime(ad1.getTime());
String user_id = getRef(position).getKey();
final String kk = user_id.toString();
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent mew = new Intent(getActivity(), ExpandActivity.class);
mew.putExtra("user_id", kk);
startActivity(mew);
}
});
}
@NonNull
@Override
public UsersViewHolder1 onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view1 = LayoutInflater.from(parent.getContext()).inflate(R.layout
.user_ad_layout, parent,
false);
return new UsersViewHolder1(view1);
}
};
searchAdapter.startListening();
mallUsers.setAdapter(searchAdapter);
}
private void loadSuggest() {
mDatabase1.orderByKey().addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postdataSnapshot : dataSnapshot.getChildren()) {
Ad item = postdataSnapshot.getValue(Ad.class);
if (item != null) {
suggestList.add(item.getTitle());
suggestList.add(item.getDescription());
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
Upvotes: 2
Views: 276
Reputation: 117
You have already experienced the lowest feature of Firebase, querying. However you can query multiple values if you for example upload on firebase both title and description like this:
user:
post:
title: "cake"
description: "yummy"
titledescription: "cake_yummy"
something like this. Another thing you can do is
private boolean hasValue = false;
private boolean hasValue1 = false;
set value is true inside onBindViewHolder and then using handler delay query values one at a time:
Handler myHandler1 = new Handler();
Runnable myRunnable1 = new Runnable() {
@Override
public void run() {
// query1 here
}
};
Handler myHandler2 = new Handler();
Runnable myRunnable2 = new Runnable() {
@Override
public void run() {
// query2 here
}
};
then you check them one at a time until it finds a value
if(!hasValue){
myHandler1.postDelayed(myRunnable1, 1000);
if(!hasValue1){
myHandler2.postDelayed(myRunnable2, 1500);
} else {
myHandler1.removeCallbacks(myRunnable1);
hasValue1 = false;
} else {
myHandler2.removeCallbacks(myRunnable2);
hasValue2 = false;
}
}
Hope it helps.
Upvotes: 0
Reputation: 138824
According to this post, there is no way in which you can pass two queries to a single adapter. So you can pass either query1
or query2
.
Unfortunately, Firebase Realtime database does not support queries on multiple properties (some people say "multiple where clauses" in SQL terms), supports only queries on a single child property. So you'll need to create an extra field to keep both fields. So to achieve this, you need to create a new field which in your database should look like this:
Firebase-root
|
--- itemId
|
--- title: "valueOfTitle"
|
--- description: "valueOfDescription"
|
--- title_description: "valueOfTitle_valueOfDescription"
So as you see, the title_description
property combines the values that you want to filter on. But Firebase real-time database doesn't support native indexing or search for text fields in objects. Additionally, downloading an entire mode to search for fields client-side isn't practical. However, you can do it for small data sets but as I said before is not practical for large data sets. To enable full text search of your Firebase real-tme database, I recommend you to use a third-party search service like Algolia.
Unlike Firebase Realtime database, Cloud Firestore allows compound queries. You should take a look at this. So a query as the one below is allowed in Cloud Firestore without creating a combined property.
itemIdRef.whereEqualTo("title", "valueOfTitle").whereEqualTo("description", "valueOfDescription");
If you want to use Algolia in Cloud Firestore, I recommend you see my answer from this post. For more information, I also recommend you see this video.
Upvotes: 1