You Can ≠ You Should
Although the wrapper can handle virtually any complex data type, it doesn't mean you should model the data in such a way, especially when dealing with the array.
When dealing with an array, avoid array of objects
not only these data types are hard to query and hard to massage, but they also pose great difficulty to security rule, especially if the permission is relying on the data.
Use array on primitive data types, if you really need to store object type, make sure it is not something that you need to query in future.
Theoretically speaking, it is possible to create a flat structure for all kinds of data types, but this is harder to be done in Firestore because your data model affects the pricing.
The pricing model incentives you to put more data in the same document, hence you see people doing all kind of array of objects.
Anyway, do not resort to array of objects types easily, create a new collection instead. Always keep your data type straightforward if possible.
Nested Object
In firestore, nested object working logic is like a flat object, as long as you get the path right, you can query and write them with no issue. A nested object is fine, as long as you structure it in how a human mind can easily comprehend it, eg do not nest too deep.
Do Not Bother Cost Focus Data Modelling
Firestore may look simple, but it is incredibly difficult to model especially if you aim to save as much as cost as possible, that is aggregating your data. My advice is, do not bother, because it increases your project complexity, and it doesn't worth the time and money to aggregate the data, unless it is a simple aggregation.
However, if aggregation can save you a significant amount of money(assuming you already model your data correctly), chances are, you are probably not using the right database, use other databases (PSQL or MongoDB), it is much better and easier in terms of cost handling.
One Collection One Document Type
It is possible to have multiple document types under the same collection. For example, under a User
collection, you may be tempted to create profile
and setting
(User/{userId}/Account/[profile and setting]
) documents in it. Or you may create two collections under User
that contains only a single document:User/{userId}/Profile/profile
and User/{userId}/Setting/setting
.
I would recommend instead of creating profile
and setting
, you create two top collections: profile
and setting
that contain all users' profiles and settings instead.
Logically, there should be one type of document in on collection(hence the name collections
).
If this is not enough to convince you: Query.
With Group Collection Query
, it is possible to query sub collection like how you query a top collection. I highly recommend that you enforce one collection one document type. This avoids you from accidentally querying another collection with the same name but has a different document type.
Speed
Don't use Firestore if speed matter. The query time of Firestore is depend on result set, not total data set, which means the more data set you have the better Firestore performs against other database.
Though it is unsure at what point Firestore performance start to exceed other databases, my guess is most people are not likely to hit that point.
Thus don't expect much from the speed, use Firestore for task that is not time critical.
Do Not Use Firestore Rules For Complex Authorization
Firestore rule sucks big time:
- You need to learn a language that is somehow similar to Javascript but is useless anywhere else
- No type safety, full YOLO mode.
- Code is not scalable and maintainable, it is nightmare to debug.
- No open source and tooling support like Javascript, you going to miss a lot of powerful validation libraries like
joi
, yup
and zod
.
Run write operations in cloud function. Yes, cloud function cost you money per invoke, but write operation is much less frequent compare to read operation, the cost is definitely lower than the cost to maintain Firestore rules.
If the cost is your concern, you can always set up a custom backend.
Read operation requires only simple authorization, but some applications may require complicated authorization, in that case, it is also better to drop all the Firestore rules and validate it via a custom backend.
One thing you will miss is the optimistic update, well until Firestore allows us to write rules in mainstream languages, we need to create our own optimistic update solutions.
Only use Firestore rule for simple authorization.
Do Not Use Offset
The server library comes with offset
cursor that is not available in the client library. However, it still charges you for all the documents that you are offsetting: source