I have some concerns about the structure for a Firestore-based project, since directly nesting documents don't seem to be an option.
To keep things simple, let's say we have a firestore DB containing data about football matches. For each match, there's a document with the player lineup, a document with a list of match events, a document with match statistics etc.
Since things like statistics, events and lineups are updated at different intervals, imported from different API calls and used in separate screens in the consuming app, I guess it's smartest to to keep them in separate documents.
I'm currently using a structure like this:
/app-data/match-lineup/matches/123456
/app-data/match-events/matches/123456
/app-data/match-statistics/matches/123456
And I then refer to it like this:
db.collection("app-data")
.doc("match-lineups")
.collection("matches")
.doc(id);
But as I add more different documents related to a match, I start getting concerns whether the current structure is an anti-pattern.
What I would prefer was a structure like this, which I find most elegant and similar to a REST URL.
/matches/123456/lineup
But that's not an option since the 123456
cannot refer to a lineup
document.
A workaround could be something like
/matches/123456/attributes/lineup
With a reference like this
db.collection("matches")
.doc(id);
.collection("attributes")
.doc("lineup")
Is this the best compromise, or are there other options that should be considered?
There is never a best and unique solution when modeling data in a NoSQL database.
IMHO, your two approaches are totally valid, since the data contained in each collection is going to be "used in separate screens in the consuming app" (i.e. there is no reason to "concentrate" all the data in one doc, as you mention). In terms of query efficiency, the two approaches are similar.
However there is another criteria you may take into account: (at the time of writing) you cannot query across collections. You may encounter a Use Case when you need to query across matches, for example all matches with a specific player in the lineup or all matches with eventType == "penalty"
. In this case you should go with approach #1 (i.e. /app-data/match-lineup/matches/123456
) since such queries across matches will be impossible with approach #2.