Reputation: 7936
I have a structure in Firebase like: (The database is Realtime Database
).
community
|--<communityID>
|--cities
| |--<locationID>:boolean
| |--<locationID>:boolean
| |--<locationID>:boolean
|--name
|--users
|-- ...
|--<communityID>
|--cities
| |--<locationID>:boolean
| |--<locationID>:boolean
| |--<locationID>:boolean
|--name
|--users
|-- ...
With other many fields.
I need to get only the communities where in the cities
list they have, match with a specific locationID
.
In other query I used something like this:
firebaseDatabase.child("users").orderByChild("location").equalsTo(<cityID>)
That works perfect when the child location
is not an "array".
So there is any way to do it?
Or I just need to bring all the communities, and then filter in the device?
Upvotes: 2
Views: 5028
Reputation: 139019
I need to get only the communities where in the cities list they have, match with a specific locationID
Unfortunately, you cannot achieve this using your actual database structure.
That works perfectly when the child location is not an "array".
It works when the location is a property of type String and not an array because the type of the object that you can pass to the equalsTo()
method was of type String and not array.
So there is any way to do it?
To solve this, you should duplicate your data. This practice is called denormalization
and is a common practice when it comes to Firebase. If you are new to NoSQL databases, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding.
Also, when you are duplicating data, there is one thing that needs to keep in mind. In the same way, you are adding data, you need to maintain it. In other words, if you want to update/delete an item, you need to do it in every place that it exists.
That being said, in your particular case, you should consider augmenting your data structure to allow a reverse lookup by creating another node named comunityCities
, where you should add as objects all corresponding communities. So your database structure should look similar to this:
Firebase-root
|
--- comunityCities
|
--- locationID
|
--- communityID
| |
| --- //Community details
|
--- communityID
|
--- //Community details
Using this schema, you can simply query the database to get all the comunities that corresponde to single location, by using the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference comunityCitiesRef = rootRef.child("comunityCities");
comunityCitiesRef.addListenerForSingleValueEvent(/* ... */);
You can read more information in my answer from the following post:
It's an answer for a Cloud Firestore question but the same rules apply in the case of the Firebase Realtime Database.
Or I just need to bring all the communities, and then filter in the device?
There's no need for that. Using this solution you'll only get the desired elements.
Upvotes: 3
Reputation: 665
I assume you are using Friebase Firestore (and not Realtime Database). Check this: https://firebase.google.com/docs/firestore/query-data/queries
There is a comparison named "array_contains". For kotlin should be a function like
val communityRef = db.collection("communityID")
val query = communityRef.whereArrayContains("cities", <locationID>)
This must be enough in this case.
By the way, if you see the "Limitations" at the end of the page it says
Cloud Firestore does not support ... Single queries across multiple collections or subcollections. Each query runs against a single collection of documents. For more information about how your data structure affects your queries, see Choose a Data Structure.
So if it is very important to query communities based on a city property, consider restructure the database or either bring all the communities and after filter it as you said. Better to restructure the database, as this may affect you app performance.
Upvotes: 2