Search code examples
iosswiftfirebasegoogle-cloud-firestoredocument

Get several ids documents firestore


How can I get ids documents from firestore?

Now I get several ids documents from backend and me need display received ids documents in tableview.

In firestore i have this ids:

xNlguCptKllobZ9XD5m1 uKDbeWxn9llz52WbWj37 82s6W3so0RAKPZFzGyl6 EF6jhVgDr52MhOILAAwf FXtsMKOTvlVhJjVCBFj8 JtThFuT4qoK4TWJGtr3n TL1fOBgIlX5C7qcSShGu UkZq3Uul5etclKepRjJF aGzLEsEGjNA9nwc4VudD dZp0qITGVlYUCFw0dS8C n0zizZzw7WTLpXxcZNC6

And for example my backend found only this ids:

JtThFuT4qoK4TWJGtr3n TL1fOBgIlX5C7qcSShGu UkZq3Uul5etclKepRjJF

or

aGzLEsEGjNA9nwc4VudD dZp0qITGVlYUCFw0dS8C n0zizZzw7WTLpXxcZNC6

Me need display only this three ids in tableview. (But in reality backend return me 100+ ids and below you can see frantic sorting these ids)

Backend append this ids in temporary array var tempIds: [String] = []

So how I can get from firestore only those ids and display their in tableview?

I use this code:

fileprivate func query(ids: String) {
    Firestore.firestore().collection(...).document(ids).getDocument{ (document, error) in
        if let doc = document, doc.exists {
            if let newModel = Halls(dictionary: doc.data()!, id: doc.documentID) {
                self.halls.append(newModel)
                self.halls.shuffle()
                self.halls.sort(by: { $0.priority > $1.priority })
                self.tableView.reloadData()
            } else {
                fatalError("Fatal error")
            }
        } else {
            return
        }
    }
}

Me need to process ids from backend in background and after process need to show processed ids in tableview without frantic sorting.

May be need use addSnapshotListened, but I don't understand how.

UPDATED CODE:

for id in idsList {
                            dispatchGroup.enter()
                            Firestore.firestore().collection(...).document(id).getDocument{ (document, error) in
                                if let doc = document, doc.exists {
                                    if let newHallModel = Halls(dictionary: doc.data()!, id: doc.documentID) {
                                        self.tempHalls.append(newHallModel)
                                        dispatchGroup.leave()
                                    } else {
                                        fatalError("Fatal error")
                                    }
                                } else {
                                    print("Document does not exist")
                                    MBProgressHUD.hide(for: self.view, animated: true)
                                    return
                                }
                            }
                        }

                        dispatchGroup.notify(queue: .global(qos: .default), execute: {

                            self.halls = self.tempHalls

                            DispatchQueue.main.async {
                                MBProgressHUD.hide(for: self.view, animated: true)
                                self.tableView.reloadData()
                            }
                        })

enter image description here


Solution

  • Getting a document by its identifier should be used when you need a single document or documents you cannot query for. Don't be hesitant to denormalize your data to make queries work, that's the point of NoSQL. If I were you, I'd either add a field to these documents so that they can be queried or denormalize this dataset set with a new collection (just for this query). However, if you still choose to fetch multiple documents by identifier, then you need to make n getDocument requests and use a dispatch group to handle their synchronization.

    let docIds = ["JtThFuT4qoK4TWJGtr3n", "TL1fOBgIlX5C7qcSShGu", "UkZq3Uul5etclKepRjJF"]
    let d = DispatchGroup()
        
    for id in docIds {
        d.enter()
        
        Firestore.firestore().collection(...).document(id).getDocument { (document, error) in
            // handle doc
            d.leave() // always leave no matter how you exit this closure
        }
    }
    
    d.notify(queue: .main, execute: {
        // here is your completion when the last leave() was called
    })
    

    All the dispatch group does is keep a count of the number of times it's entered and left and when they match, it calls its notify(queue:execute:) method (its completion handler).