I am a beginner and my firestore database has a collection which has documents and each document has a subcollection without any other fields. I can't find a way to access the ID of the empty document and get the subcollection associated with the doc using the SDK. I could do it on console but I have to too much to do and cannot also make changes to my application for now so I need to use the SDK. Please suggest me some way to access them like the console.
If you know how the CollectionReference of the sub-collection, you can easily get the parent DocumentReference with parent property of the CollectionReference. From the DocumentReference you just need to use the id property.
You didn't share much details on your data model, so it is difficult to give more guidance on how to find the CollectionReference. Mark's answer presents some possible approaches.
So, I used collection group query(collectionGroup) to query the documents in the subcollections(which have the same ids) and found the IDs of the parent document by the parent property.
Huge thanks to #mark carlton and #Renaud Tarnec for these suggestions.
CASE 1: If the subcollections are queried across multiple documents, you could use a collection group query which queries collections of the same name regardless of their position in the hierarchy. This way you don't actually need to know the ID of the document
CASE 2: Use a document ID you will remember for such a case as opposed to having a UID for the ID. This was your queries make much more sense to you
Related
I am working on a social Flutter app where there is a section for posts. Each post can have comments and each comment can have replies which are different from comment in class level. I am using Firebase Firestore as my backend. As the official docs for Firestore states that there are three ways to structure our data as follows: top-level collection, document and subcollection (collection inside of a document). In my app, for posts I have a top-level collection called posts which consists all of the posts. Now that each post can have thousands of comments, so storing comments inside each post document as a map value is not a good idea as it will cross the limit of 1MB per document and also adding and deleting a comment would be so hard. So now I can not decide whether I should create a top-level collection for comments or a subcollection for comments in each post document. It's the same for replies of each comment. Should I again create another top-level collection for replies or a subcollection for replies in each comment document? I strongly appreciate your advice and help!
So now I can not decide whether I should create a top-level collection
for comments or a subcollection for comments in each post document.
There is no difference from a technical or performance perspective since:
A Firestore query performance is proportional to the size of your result set, not your data set (i.e. the number of docs in the collection);
You can, with Collection Group queries, query all the documents of all collections with the same ID (i.e. comments or replies).
The main difference is probably that in the Firestore console you can easily display the sub-collection of a specific post.
Note that if you choose to go for root collections for comments or replies you should not forget to save the parents IDs in these children docs in such a way you can query the one corresponding to a specific parent.
I have an object stored in the Firestore database. Among other keys, it has a userId of the user who created it. I now want to store an email address, which is a sensitive piece of info, in the object. However, I only want this email address to be retrieved by the logged in user whose userId is equal to the userId of the object. Is it possible to restrict this using Firebase rules? Or will I need to store that email address in a /private collection under the Firebase object, apply restrictive firebase rules, and then retrieve it using my server?
TL;DR: Firestore document reads are all or nothing. Meaning, you can't retrieve a partial object from Firestore. So there is no feature at rule level that will give you granularity to restrict access to a specific field. Best approach is to create a subcollection with the sensitive fields and apply rules to it.
Taken from the documentation:
Reads in Cloud Firestore are performed at the document level. You either retrieve the full document, or you retrieve nothing. There is no way to retrieve a partial document. It is impossible using security rules alone to prevent users from reading specific fields within a document.
We solved this in two very similar approaches:
As you suggested, you can move your fields to a /private collection and apply rules there. However, this approach caused some issues for us because the /private collection is completely dettached from the original doc. Solving references implied multiple queries and extra calls to FS.
The second option -which is what the Documentation suggests also, and IMHO a bit better- is to use a subcollection. Which is pretty much the same as a collection but it keeps a hierarchical relationship with the parent coll.
From the same docs:
If there are certain fields within a document that you want to keep hidden from some users, the best way would be to put them in a separate document. For instance, you might consider creating a document in a private subcollection
NOTE:
Those Docs also include a good step-by-step on how to create this kind of structure on FS, how to apply rules to them, and how to consume the collections in various languages
I'm trying to clean up my Google Cloud Firestore database, and I have some subcollections with no parent doc (the parent was deleted). How can I find all of those, using the Firebase Admin SDK, so I can delete them?
You will end up writing a lot of code for this. I'm going to link to nodejs APIs.
For each collection where there could be missing documents, you will need to need to query that collection with listDocuments(). That will return a list of all documents in the collection, including the missing documents that have subcollections. You will then need to iterate the DocumentReferences returned in that list, and call get() on every one of them. The returned DocumentSnapshot will then tell you if it exists or not using its exists property.
After you have all the DocumentReference objects referring to missing documents, you can then follow the instructions in this other question that describes how to delete all nested subcollections under that DocumentReference, go straight to the Firebase documentation.
I need to create a firestore doc which also has a collection, ideally in a single write operation.
I'm not seeing anything like this in the documentation, so failing that any tips on getting the created doc id and then adding multiple documents to a collection?
Edit: I'm developing in typescript/js
You can use a transaction or batch write to perform atomic operations among multiple documents. In both cases, you need to know all the IDs for all the documents you want to create ahead of time. You don't need to create a document in order for there to be a subcollection. Documents don't actually "contain" subcollection. Subcollections are currently just a technique for organizing your data.
It wasn't really clear from your question, but if your first document requires a generated ID, you can use the example code in the documentation that generates a DocumentReference object, which you can populate later in your transaction or batch.
Since you didn't say which language or system you're working on, I don't know which code sample to show here from the docs, so you'll have to go to the documentation linked here to see how it works. You'll end up using a method called "doc" or "document" on a CollectionReference to generate the DocumentReference with the generated ID.
I want to write a recursive function in which I can pass in a document reference and delete that document and it's subcollections. I was thinking that the base case would be that the document has no subcollections. If it has a subcollection, I would pass that subcollection into the recursive function, and delete any existing documents. If not, I would simply delete that document and return. So is there someway I can check if a document has a subcollection, and if so retrieve it?
According to Doug Stevenson here there are no client SDK APIs for listing subcollections of a document.
Although you may find your answer here but that also may create further problems. In documentation also deleting collections from an Android client is not recommended.