There are two parts to your question. Let me try to answer them individually.
How to handle nested data structures in Firestore / Codable?
Any attribute on a Codable
struct will be mapped against the respective attribute on a Firestore document (you have some influence over thus by using the CodingKeys
enum - see this article.
Nested types will be mapped to dictionaries on the document, whereas arrays and other sequences will be mapped to arrays on the document.
In order to retrieve a sub-collection of a document, you will need to perform a separate fetch request. Firestore doesn't support fetching a nested tree of documents/sub-collections on the client. It's a different story on the server, though. Check out Renaud's article to learn more about this.
How to store user-specific data?
For any user=specific data, I would recommend one of the following two ways to structure your data:
Storing as a sub-collection
In this scenario, we have one top-level collection users
, which contains documents for all your users (let Firestore auto-generate the document IDs for you, and store Firebase Auth's user ID as an attribute on the respective user
document.
/(root)
+ users <-- (collection)
+ 0FABQ...RiGg <-- (user document)
- uid: "6ZPt...BLiK3fnl2" <-- (Firebase Auth user ID)
- name: "Johnny Appleseed" <-- (attribute)
+ recipes (collection) <-- (sub-collection)
+ A69EF...4EFA <-- (recipe document)
- name: "Scones" <-- (attribute)
+ FCED...12D5 <-- (another user document)
You can then use the user's ID (from Firebase Auth) to query all the user's recipes.
Storing as a top-level collection
In this scenario, we have two top-level collections: one for all your users, and another one for all the recipes. In order to distinguish a user's recipes, each recipe doc has a uid
attribute which contains the respective user's user ID:
/(root)
+ users <-- (collection)
+ 0FABQ...RiGg <-- (user document)
- uid: "6ZPt...BLiK3fnl2" <-- (Firebase Auth user ID)
- name: "Johnny Appleseed" <-- (attribute)
+ FCED...12D5 <-- (another user document)
+ recipes (collection) <-- (collection)
+ A69EF...4EFA <-- (recipe document)
- uid: "6ZPt...BLiK3fnl2" <-- (Firebase Auth user ID)
- name: "Scones" <-- (attribute)
To retrieve a user's recipes, you query all recipes and filter for the ones that match the user ID of the currently signed in user.
To learn more about Firestore data modelling, check out the documentation, which also contains links to a number of really useful videos. Fireship also has a really good article about this.