Welcome to 16892 Developer Community-Open, Learning,Share
menu search
person

Categories

I want to create a simple SwiftUI app that uses FireStore and has a collection "recipes" and a collection "users" for user specific data. In the users collection, I want to add a document for every user that holds a sub-collection with the favourite recipes of the user.

On the client side, I am using something like this for the user data:

import FirebaseFirestoreSwift
import Foundation

struct Account: Codable {
    @DocumentID var id: String?
    var favoriteRecipes = Set<Recipe>()
}

Now if I write the document to firebase using the Codable support, it creates a Map for the set of recipes (which is fine I guess, I just want to have it another way).

So I obviously can handle the sub-collection "manually" and use it like any other stand-alone collection.

Nevertheless, I am wondering if there is some sort of "Best-Practice" for handling sub-collections in Firebase with Codable in Swift?

Thanks a lot!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
569 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to 16892 Developer Community-Open, Learning and Share
...