If your app will be widely used, nesting lots of "doctors" within a single document, might not be the best solution. The best scalable way to store a large list of data in Firestore is using documents in a collection. It's true that an array is a supported data-type, but this type of field doesn't scale for growing lists. There is also another issue, the documents in Firestore have limits. So there are some limits when it comes to how much data you can put into a document. According to the official documentation regarding usage and limits:
Maximum size for a document: 1 MiB (1,048,576 bytes)
As you can see, you are limited to 1 MiB total of data in a single document. When we are talking about storing text, you can store pretty much but as your array gets bigger, you might exceed this limitation, which will obviously cause problems at scale. This approach is also generally considered a bad design.
So a viable schema for your data should look like this:
Firestore-root
|
--- doctors
|
--- $doctorId
|
--- name: "Doctor Name"
|
--- phoneNumbers: ["+91...", "+91..."]
|
--- specialization: ["cardiology", "dermatology"]
As you can see, both" phoneNumbers" and "specialization" properties are arrays. Now it's recommended to store data in arrays as each one of them will hold a small amount of data.
Ultimately I want to query for the specialization array as efficiently as possible
To get all the doctors with a specific specialization, for example "cardiology", please use the following lines of code:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference doctorsRef = rootRef.collection("doctors");
doctorsRef.whereArrayContains("doctors", "cardiology").addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d("TAG", document.getString("name"));
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
The result in the logcat will be:
Doctor Name
P.S. Always consider storing the name of the fields in your class to match the ones in the database.
Edit:
Would it be possible to query the specialization and days together in a single collection?
If the days will also be an array, no you cannot because there is another limitation:
You can use at most one array-contains clause per query. You can't combine array-contains with array-contains-any.
If you want to query according to multiple values, then you should consider not using arrays at all, but simple properties:
Firestore-root
|
--- doctors
|
--- $doctorId
|
--- name: "Doctor Name"
|
--- phoneNumbers: ["+91...", "+91..."]
|
--- specializationOne: "cardiology"
|
--- specializationTwo: "dermatology"
|
--- dayOne: "Monday"
Then use a query that looks like this:
doctorsRef.whereEqualTo("specializationOne", "cardiology").whereEqualTo("dayOne", "Monday").addOnCompleteListener(/* ... /*);