Harry Stanford
Harry Stanford

Reputation: 122

How can I reference second level collections in Firebase?

Currently my Firebase database is using the following structure

Users

However I have created a new collection inside of the "users" collection called "products" which will store product details that users have uploaded on the application.

How can I ensure that once a user uploads a new product, it is only uploaded into their 'User X data' dataset, inside the respective "products" collection. The code I currently have only uploads the data into the "users" collection, with no reference of the users who added the product as required. I have shown the structure of my Firebase database below for reference.

enter image description here

Here is my code:

 let user = Auth.auth().currentUser

    db.collection("users").getDocuments { (snapshot, error) in
            if let error = error {
                print(error)
                return
            } else {
                for document in snapshot!.documents {
                    let data = document.data()
                    let userId = data["uid"] as! String
                    if userId == user?.uid {
              
                        db.collection("users").document("products").setData(["productNameField":firstName, "productURLField":lastName,"productPriceField":ebayName, "productDescriptionField":etsyName, "productTimeRemainingField":email])
                        
                        
                    }
                }
            }
        }

How would I go about updating my code to achieve this?

Upvotes: 0

Views: 385

Answers (2)

LeadDreamer
LeadDreamer

Reputation: 3499

You're wastefully looping over the entire list of users to FIND the user document needed. Simplify, simplify - use the user.uid as the Id of the user document!! (i.e. when you create the user document, save it as

db.collection("users").doc(user.uid).set({whatever})

...then it's trivial to access as...

 let user = Auth.auth().currentUser
 
  db
  .collection("users")
  .doc(user.uid)
  .collection("products")
  .setData([
    "productNameField":firstName,
    "productURLField":lastName,
    "productPriceField":ebayName,
    "productDescriptionField":etsyName,
    "productTimeRemainingField":email
  ]);

If there is another reason to keep the docID and the uid separate (not shown here), then use a query to get the SPECIFIC document with the uid, rather than downloading ALL of them

let user = Auth.auth().currentUser

    db
    .collection("users")
    .where(field: "uid", opStr:"==", value: user.uid)
    .getDocuments( { (snapshot, error) in
        if let error = error {
            print(error)
            return
        } else { //the query should only return the one document, but queries always return an array
            snapshot
            .documents[0]
            .ref()
            .document("products")
            .setData([
              "productNameField":firstName,
              "productURLField":lastName,
              "productPriceField":ebayName,
              "productDescriptionField":etsyName,
              "productTimeRemainingField":email
              ])
         }
      }
...etc...

I don't generally use Swift, so the where clause may require different formatting, but the idea is GET ONLY THE DOCUMENT YOU NEED. Your security rules should only be allowing this, anyway.

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 598785

I think you're looking for

let user = Auth.auth().currentUser

db.collection("users").getDocuments { (snapshot, error) in
        if let error = error {
            print(error)
            return
        } else {
            for document in snapshot!.documents {
                let data = document.data()
                let userId = data["uid"] as! String
                if userId == user?.uid {              
                document.reference.collection("products").addDocument(["productNameField":firstName, "productURLField":lastName,"productPriceField":ebayName, "productDescriptionField":etsyName, "productTimeRemainingField":email])
                }
            }
        }
    }

So here document is the DocumentSnapshot that you're looping over, so document.reference gives you the reference to that specific document, and document.reference.collection("products") then points to the `products subcollection for that specific document.

Upvotes: 1

Related Questions