Is there any way I could search by any Reatime Firebase Database field? Right now I know how to search by FP_CarNumber, but I would like to search by others as well like SP_CarNumber or SP_CarNumber and FP_CarNumber at the same time.
private void txtSearch(String str){
FirebaseRecyclerOptions<MainModel> options =
new FirebaseRecyclerOptions.Builder<MainModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("Declaration_Data").child(currentuser).child("Declarations").orderByChild("FP_CarNumber").startAt(str).endAt(str + "\uf8ff"), MainModel.class)
.build();
mainAdapter = new MainAdapter(options);
mainAdapter.startListening();
recyclerView.setAdapter(mainAdapter);
}
The Realtime Database only supports queries on single field property. I have explained in one o my answers:
How to sort Firebase records by two fields (Android)
How to solve such a situation by creating an extra field to keep the other values. Unfortunately, that workaround doesn't apply to all situations.
Besides that, as far as I know, there is no library that does that automatically in Android. However, there is one for the web, written by David East called Querybase.
So unlike in the Realtime Database, Cloud Firestore allows compound queries. So I recommend you try that.
Related
I want to save the data on Firebase, that a user describes on an Intent. The saved data should be used to find one or more matching users with similar informations.
Thanks in forward.
Looks like you are building an app where you can clusters users with similar interests about particular thing, i would suggest you to use firebase firestore for storing data, and you can retrieve data that are similar using the firebase simple and compound query depending on your requirement.
Trying to fetch related data from firebase
I am new in Android and I am stuck here, want to retrieve data from Firebase where "del_id = 1" and "date = 2019-3-18" but I don't know how to write as Firebase way to retrieve what I want, Image above will further demonstrate what I have tried and what I want.
Your answer will be highly valuable for me.
The following line of code:
invSnapsjot.getValue(Invoice.class)
Returns an object of type Invoice and not a DataSnapshot object so you can call .child() method on it.
If you want to get a specific element (del_id = 1), you should simply use a query that looks like this:
myDatabase.orderByChild("del_id").equalTo("1").addValueEventListener(/* ... */);
Unfortunately, Firebase realtime database does not support queries on multiple properties but there is still a workaround for that, so please see my answer from the following post:
How to sort Firebase records by two fields (Android)
If you want to write or update value at that time you need to take .addValueEventListener
If you want to only set your value in firebase you directly set value without using .addValueEventListener
More details refer this link
https://firebase.google.com/docs/database/android/read-and-write
As for similar questions on this topic and on ChildEventListener, there is no relevant answer, so heres mine.
I have a local SQLite DB which holds all the data, I also have Firebase realtime database which I'm updating with new entries or real time changes across all users. I'm currently doing it with the use of ChildEventListener as follows:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getDatabase().getReference();
DatabaseReference childRef = rootRef.child("my_root");
ChildEventListener eventListener = new ChildEventListener()
{
....
};
childRef.addChildEventListener(eventListener);
As for functionality, With this code I can get realtime changes on childs, get new entries, deleted childs and everything I need but there is one problem. When this specific activity with the listener loads up, the onChildAdded listener gets called enormous amounts of times for every child on this root, as stated on the documentation:
child_added is triggered once for each existing child and then again every time a new child is added to the specified path
So I though to gain focus on the items that I really need and I have done it with:
rootRef.orderByKey().startAt("-WhatTF123456789")...
But then I have lost my CRUD capabilities because it's listening to the new entries and not all of them.
So I came up with a solution. Keep node with all the changes that has been made to the FireBase database and a node with all the users that have read and made the changes to the local DB to know who needs an update, Then use addChildEventListener to this specific node. But that seems redundant.
What is my options to handle this kind of situation?
The onChildAdded listener gets called enormous amounts of times for every child on this root.
As you already mentioned and as the docs states, this is the expected behaviour. Usually, is not recommended to attach a ChildEventListener on a node (root node) that contains huge amount of data. Please be careful about this practice because when downloading large amount of data, you can get erros like: OutOfMemoryError. This is happening because you implicitly download the entire node that you are listening to, along with all the data beneath it. That data might be present as simple properties or, as complex objects. So it can be considered a waste of resource and bandwidth. In this case, the best approach is to flatten the database as much as possible. If you are new to NoSQL databases, this practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, I recommend you take a look at:
This video, Denormalization is normal with the Firebase Database.
Official docs regarding Best practices for data structure in Firebase realtime database.
My answer from this post: What is denormalization in Firebase Cloud Firestore?
This article, Structuring your Firebase Data correctly for a Complex App.
This article, NoSQL data modeling techniques.
Please also note that when you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.
I also recommend you to see the last part of my answer from the following post:
What is the correct way to structure this kind of data in firestore?
It is for Cloud Firestore but same rules apply to Firebase realtime database.
But then I have lost my CRUD capabilities because it's listening to the new entries and not all of them.
Everything in Firebase is about listeners. You cannot get realtime updates for objects within a node, unless you are listening to them. So you cannot limit the results and expect to get updates from objects that you are not listening to. If you need to get updates for all objects within a node, you need to listen to all of them. Because this approach isn't practical at all, you can either use denormalization as explained above or to restrict the results by using queries that can help you limit the amount of data that you get from the database. Regarding your solutions, the second one is much preferred but you can also consider another approach which would be to load data in smaller chunks according to a timestamp property, or according to any other property that you need.
Edit: According to your comment:
Can you please provide tests for each solution (1.denormalization, 2.my solution) examine use of bandwidth and resources and which one is really preferred?
All data is modeled to allow the use-cases that an app requires. Unfortunately, I cannot do tests because it really depends on the use-case of the app and the amount of data that it contains. This means that what works for one app, may be insufficient for another app. So the tests might not be correct for everyone. The denormalization process or your solution is entirely dependent on how you intend to query the database. In the list above, I have added a new resource which is an answer of mine regarding the denormalization tehnique in NoSQL databases. Hope it will also help feature visitors.
I would make a root node with the name, for example, MaintenanceUpdate.
All clients are subscribed to changes here.
As soon as MaintenanceUpdate becomes = true, all clients unsubscribe from changes to the main "database". And then (when MaintenanceUpdate = false) are re-subscribed again.
At this time you are updating the database.
I have similar requirements, with Firebase and Room, while I've solved it alike this:
public class BaseModel extends BaseObservable implements IDataModel {
/** Sqlite default PK */
private int itemId = 0;
/** Firebase uniqueId */
#ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_UNIQUE_ID)
protected String uniqueId = null;
/** Firebase lastSync */
#ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_LAST_SYNC)
protected long lastSync = 0;
...
}
this means, when a local record has a KEY_FIREBASE_UNIQUE_ID which is null and the KEY_FIREBASE_LAST_SYNC is 0, it has to be inserted into Firebase - else it would check, when running a synchronization AsyncTask, if the local or remote record needs to be updated. this is because the main issue is, that when inserting remotely, the ChildEventListener will attempt to synchronize duplicates to the same client - unless having such indicators for the synchronization status in place, locally and remotely. the local primary keys might vary across the clients (depending for how long they were offline and how many records where locally inserted during the offline state), while the synthetic KEY_FIREBASE_UNIQUE_ID is used for identifying them; it's the "key to success".
Basically summed up in the title, I would like to make it so that each new document being created in a particular collection has an increment sort of serial number to it. This is for properly tracking the new orders that are written to the database. AutoID is random and causes sorting issues, I would like the data to be easily manageable. Is this possible to achieve via Cloud Functions? Any sample code snippets I can look at? Thank you!
Use firebase.firestore.FieldValue.serverTimestamp. It will be set by the server to nanosecond resolution.
firebase.firestore().collection('stuff').add({
sort: firebase.firestore.FieldValue.serverTimestamp(),
});
As per #Frank van Puffelen comment, "Using sequential IDs for that is an anti-pattern". Your use case is also mentioned in the Firestore documentation here:
Important: Unlike "push IDs" in the Firebase Realtime Database, Cloud
Firestore auto-generated IDs do not provide any automatic ordering. If
you want to be able to order your documents by creation date, you
should store a timestamp as a field in the documents.
I have a list of users with their names in the Firestore database. What I am trying to achieve is to make users able to search and find other users. My problem is that:
Query query = db.collection("users").whereEqualTo("name", searchTerm);
FirestoreRecyclerOptions<UserObject> response = new FirestoreRecyclerOptions.Builder<UserObject>()
.setQuery(query, UserObject.class)
.build();
In the code above, I am able to find users only if I write their first and last name exactly right. But what I want is to get users that do have similar names or last names. And also, users' last and first names are stored in one string variable. Like in facebook, if you search some names, it will display the similar names as well. Is there a good way to achieve that with firestore?
As per official documentation:
Cloud Firestore doesn't support native indexing or search for text fields in documents. Additionally, downloading an entire collection to search for fields client-side isn't practical.
So I strongly recommend you not to download the entire collection in order to create a search, isn't worth it. But in order to have a slightly better search, I recommend you use the following query:
Query query = db.collection("users").startAt(searchText).endAt(searchText+ "\uf8ff");
If this query isn't what you are searching for, I recommend you use Algolia search, which is also recommended by Firebase. I also recommend you see this video.
Late answer but for anyone who's still looking for an answer try this.
Query query = db.collection("users").whereGreaterThanOrEqualTo("name", searchTerm);