I am creating a simple social media app in Android Kotlin with FireStore.
In the user registration page, after user inputs all the basic information I create a collection called "users" like so:
db.collection("users").document(mUser.uid).collection("basicUserInfo").add(info)
In another page where users search for other users, I am trying to read the collection I made above to read specific users data like so :
db.collection("users").get()
but the returned result contains 0 documents in it even though in FireBase Console I can see there are 5 documents in it.
On the other hand, when I try creating a collection "users" manually on the firebase console with some documents in it, the app reads the documents successfully, returning the correct size.
So I am assuming the problem lies in the way I initiate the collection "users" from the app side.
Do you know why this doesn’t work yet when created manually it works?
2
Answers
The first line of code you shared creates a document in the
basicUserInfo
subcollection. It does not create a document in theusers
collection.That’s why when you read all documents from the
users
collection in your second line of code, you get no results: you never created a document in the users collection.You can see this in the Firestore console, as the document ID in the users collection is shown in italics. If you search for Firestore documents in italics here on Stack Overflow, you’ll find more questions from developers about this.
If you want to be able to read the document form the
users
collection, you’ll have to create a document there too. The document can be empty, but it does have to exist in order to read it.Cloud Firestore queries are shallow and this behaviour is intentional.
Here "shallow" means that when you query for documents in the
/users
collection (like withdb.collection("users").get()
), it does just that. A document that is in a subcollection of a document in/users
is considered to be in a different collection and will not be returned in that first query.While now a little dated, I recommend reviewing the first few videos of the Getting to Know Cloud Firestore playlist. The second video of the series covers what I’m going to cover below.
Looking at this line:
Your database contains a
/users
collection that contains documents named with the User ID of each user. Each of these user documents have a/basicUserInfo
subcollection that contains some basic user information in a document with an auto-generated document ID.Imagining that your database contains no data and looks like this:
Note: Empty collections don’t actually exist in Cloud Firestore. I’m showing a collection here as an empty array for the sake of illustrating your issue.
As a user signs up, you authenticate them, collect some user info (your
info
object) and then store this to your database using:Your database now looks like this:
As can be seen above, the
/users
collection is still empty. This is because the user’s own document was not created or set with any data directly. This would be achieved using:As an admin using the Firebase console for Cloud Firestore, you would want to know of these subcollections, so it displays them in its interface. This behaviour is covered by the documentation on Non-existent ancestor documents:
In the example we’ve walked through so far, the
/users/vRIos3pKKjg9mkQzGKcdtQ4Iuhp2
document will appear in the Firebase data viewer in italics and the nested data will show in the subcollections panel along with the generated document.This behaviour is why your "/users" query does not return any results and is pointed out by the warning that follows the above screenshot:
When you create a document in Cloud Firestore using the data viewer, you first create the user ID document in the
users
collection, then start a new subcollection, and then create thebasicUserInfo
document.An important difference between your code and the manual steps is that you create the user ID document in the
users
collection. This is why the behaviour is different between the two approaches.To replicate what you are doing in the Firestore data viewer, you need to add a line to create the user ID document:
There are two ways that you can handle this problem.
Option 1: Use a collection group query
Using a collection group query, you can find all documents that are nested under collections called "basicUserInfo".
If you use this approach, I would recommend swapping
add(info)
fordocument(mUser.uid).set(info)
so that the document ID is also the user’s ID rather than an auto-generated one.Option 2: Restructure
To avoid this problem and to also keep sensitive information private, you could split the nested subcollection out to its own collection rather than unnecessarily nest it in its own collection.
Then in your interface, you can use
/profiles
for your query and to also help users search each other.