I have a tree-like structure with subcollections that I can build, insert objects into and fetch from, but I cannot list the documents in the middle. The tree looks like
/TimeEntries/2018/2018-10/2018-10-15/Events
/TimeEntries/2018/2018-10/2018-10-22/Events
In the above, 2018
is a document, 2018-10
is a subcollection, and 2018-10-15
and 2018-10-22
are documents with Events
subcollections.
This is made with something like
func SaveEvents(week time.Time, events []Event) {
colref := client.Collection("TimeEntries").Doc(week.Format("2006")).Collection(week.Format("2006-01")).Doc(week.Format("2006-01-02")).Collection("Events")
batch := client.Batch()
for _, event := range events {
batch.Set(colref.Doc(strconv.Itoa(event.Id)), event)
}
if _, err := batch.Commit(context.Background()); err != nil {
log.Fatalf("unable to create event docs: %v", err)
}
}
There are times when I'll want events by week and events by month. I can fetch events by week right now, but to fetch events by month I have to fetch the list of documents in the middle of the tree, and then get their subcollections' documents. Unfortunately, trying to list the documents in the middle of the tree doesn't work; this always logs 0 events
:
func FetchEventsForMonth(week time.Time) {
colref := client.Collection("TimeEntries").Doc(week.Format("2006")).Collection(week.Format("2006-01"))
snaps, err := colref.Documents(context.Background()).GetAll()
if err != nil {
log.Printf("cannot fetch docs: %v", err)
return
}
log.Printf("%d events", len(snaps))
}
I can't see anything in the documentation that explains this behavior. What am I missing?
When you are using the following collection reference:
colref := client.Collection("TimeEntries").Doc(week.Format("2006")).Collection(week.Format("2006-01"))
It means that you are getting from the database only the documents within 2006-01
collection and only those documents, nothing more. Unfortunately, there is no way in Firestore to also get all the documents within Events
collection, which is a subcollection within 2006-01-02
document in a single query. Queries in Firestore are shallow: they only get items from the collection that the query is run against. There is no way to get documents from another top-level collection and other collections or subcollections in a single query. Firestore doesn't support queries across different collections in one step. A single query may only use properties of documents in a single collection.
If you want to query your Cloud Firestore database for documents within a single collection by documentId
, you can achieve this using FieldPath.documentId()
like this:
client.collection.where(firebase.firestore.FieldPath.documentId(), '<', 'yourDate').get();
But be aware that the document ids are String and therefore this will include documents with id like 2018-10-15
or 2018-10-22
. So when you order strings, the result are ordered lexicographically and I think that this is not what you want. So if you want to query a collection by numeric values, you'll need to write the document ID as a numeric value.
But the most efficient solution in this case would be to simplify your database by creating a single collection that holds event
documents and add under each event object a date property so you can query your database according to it. In this case you can use all the functions that Firestore SDK provides and filter with a range comparison (<, <=, >, >=).