John
John

Reputation: 25

Filter Firebase Data SwiftUI

This code adds all the data in a single array. In HomeViev I use to Foreach and I added to data to list. But I have to split the data in two. status collection has two type "active" and "closed" but I don't know how can I filter

import SwiftUI
import Combine
import Firebase

let dbCollection = Firestore.firestore().collection("Signals")

class FirebaseSession : ObservableObject {

    @Published var session: User? { didSet { self.didChange.send(self) }}
    @Published var data = [Signal]()

    var didChange = PassthroughSubject<FirebaseSession, Never>()
    var handle: AuthStateDidChangeListenerHandle?


    func listen () {
        handle = Auth.auth().addStateDidChangeListener { (auth, user) in
            if let user = user {
                print("Got user: \(user)")
                self.session = User(uid: user.uid, email: user.email)
                self.readData()
            } else {
                self.session = nil
            }
        }
    }

    func readData() {
        dbCollection.addSnapshotListener { (documentSnapshot, err) in
            if err != nil {
                print((err?.localizedDescription)!)
                return
            }else {
                print("read data success")
            }

            documentSnapshot!.documentChanges.forEach { i in

// Read real time created data from server

            if i.type == .added {
                let id = i.document.documentID
                let symbol = i.document.get("symbol") as? String ?? ""
                let status = i.document.get("status") as? String ?? ""
                self.data.append(Signal(id: id, symbol: symbol, status: status))
            }

// Read real time modify data from server

            if i.type == .modified {
                self.data = self.data.map { (eachData) -> Signal in
                    var data = eachData
                    if data.id == i.document.documentID {
                        data.symbol = i.document.get("symbol") as! String
                        data.status = i.document.get("status") as? String ?? ""
                        return data
                    }else {
                        return eachData
                    }
                }
            }

// When data is removed...

            if i.type == .removed {
                let id = i.document.documentID
                for i in 0..<self.data.count{
                    if self.data[i].id == id{
                        self.data.remove(at: i)
                        return
                    }
                }
            }
        }
    }
}

}

Upvotes: 0

Views: 1097

Answers (1)

Jay
Jay

Reputation: 35648

The question states

But I have to split the data in two

I assume that means two arrays; one for active and one for closed.

var activeData = [...
var closedData = [...

There are a couple of ways to do that

1) Query Firestore for all status fields equal to active and load those documents into the active array and then another query for status fields equal closed and load those in the the closed array

2) I would suggest a simpler approach

if i.type == .added {
   let id = i.document.documentID
   let symbol = i.document.get("symbol") as? String ?? ""
   let status = i.document.get("status") as? String ?? ""

   if status == "active" {
      self.activeData.append(Signal(id: id, symbol: symbol, status: status))
   } else {
      self.closedData.append(Signal(id: id, symbol: symbol, status: status))
   }
}

and do the same thing within .modified and .removed; identify the status so the code will know which array to remove it from.

EDIT:

Based on a comment

I don't know how to query this codes.

I am providing code to query for signals that are active. This code will return only active signals and as signals become active, inactive etc, this will modify a signalArray to stay in sync with the data.

let dbCollection = Firestore.firestore().collection("Signals")
let query = dbCollection.whereField("status", isEqualTo: "active").addSnapshotListener( { querySnapshot, error in
    guard let snapshot = querySnapshot else {
        print("Error fetching snapshots: \(error!)")
        return
    }

    snapshot.documentChanges.forEach { diff in
        if (diff.type == .added) {
            let signalToAdd = Signal(withDoc: diff.document)
            self.signalArray.append(signalToAdd)
        }
        if (diff.type == .modified) {
            let docId = diff.document.documentID
            if let indexOfSignalToModify = self.signalArray.firstIndex(where: { $0.signal_id == docId} ) {
                let signalToModify = self.signalArray[indexOfSignalToModify]
                signalToModify.updateProperties(withDoc: diff.document)
            }
        }
        if (diff.type == .removed) {
            let docId = diff.document.documentID
            if let indexOfSignalToRemove = self.signalArray.firstIndex(where: { $0.signal_id == docId} ) {
                self.signalArray.remove(at: indexOfSignalToRemove)
            }
        }
    }
})

Note that my Signal Class has an initializer that accepts a QueryDocumentSnapshot to initialize it as well as a .updateProperties function to update its internal properties.

Upvotes: 2

Related Questions