skip to Main Content

Hi there,
Ive been coding an app for my friend and me recently and currently I’m implementing Google Firebase’s Firestore Database. I have set up a Data Model and a View Model to handle data to my view. Bear in mind I’m still new to Swift(UI) so my code might be a little messy.

This is where the database is accessed and the data is put into the data model.
Friends_Model.swift

import Foundation
import Firebase
import FirebaseFirestore

class Friends_Model: ObservableObject {
 
    
    @Published var friend_list = [Friends_Data]()
    @Published var noFriends = false
    
    func getData() {
        let db = Firestore.firestore()
        
        db.collection("users").getDocuments { snapshot, error in
            
            //check for errors
            if error == nil {
                print("no errors")
                
                if let snapshot = snapshot {
                    
                    //Update the list property in main thread
                    DispatchQueue.main.async {
                        //get all docs and create friend list
                        
                            self.friend_list = snapshot.documents.map { d in
                                
                                    //Create friend item for each document
                                    return Friends_Data(id: d.documentID,
                                                        userID: d["userID"] as? String ?? "")
                            }
                    }
                }
                
            } else {
                // handle error
            }
            
        }
        
        
    }
}

This is my data model. To my understanding this just sets the variables.
Friends_Data.swift

import Foundation

struct Friends_Data: Identifiable {
    

    var id: String
    var userID: String
}

This is my actual view where I output the data (just the relevant part ofc).
FriendsPanel.swift (Swift View File)

// var body etc. etc.
if let user = user {
            let uid = user.uid ?? "error: uid"
            let email = user.email ?? "error: email"
            let displayName = user.displayName
        
            VStack {
                Group{
                    Text("Your Friends")
                        .font(.title)
                        .fontWeight(.bold)
                }
                
                List (friends_model.friend_list) { item in
                    Text(item.userID)
                }
                .refreshable {
                    friends_model.getData()
                }
            }
// further code

Displaying all entries in the database works fine, though I’d wish to only display the entries with the attribute "friendsWith" having the same string as oneself (uid).

Something like

if friends_model.friends_list.userID == uid {
 // display List
} else {
 Text("You don't have any friends")
}

I couldn’t work it out yet, although I’ve been going on and about for the past 2 hours now trying to solve this. Any help would be greatly appreciated. Also sorry if I forgot to add anything.

2

Answers


  1. Load only the data you need:

    Use a query:

    let queryRef = db.collection("users").whereField("friendsWith", isEqualTo: uid)
    

    and then:

    queryRef.getDocuments { snapshot, error in......
    

    Here you can find more about firestore:

    https://firebase.google.com/docs/firestore/query-data/queries

    Login or Signup to reply.
  2. You need to make a View that you init with friends_model.friend_list and store it in a let friendList. In that View you need an onChange(of: friendList) and then filter the list and set it on an @State var filteredFriendList. Then in the same view just do your List(filteredFriendList) { friend in

    e.g.

    struct FiltererdFriendView: View {
        let friendList: [Friend] // body runs when this is different from prev init.
        @State var filteredFriendList = [Friend]()
    
        // this body will run whenever a new friendList is supplied to init, e.g. after getData was called by a parent View and the parent body runs.
        var body: some View {
             List(filteredFriendList) { friend in
                 ...
             }
             .onChange(of: friendList) { fl in
                 // in your case this will be called every time the body is run but if you took another param to init that changed then body would run but this won't.
                 filteredFriendList = fl.filter ...
             }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search