Firestore reads specific collection data - ios

This is my firestore, I want to read all the data in the "RechargeCoin" collection, I tried many ways but can't, who can help me
--> Users/uid/RechargeCoin/postid
I want to get all the contents of "UID" and "PostID", how should I do it?
Here is my code
let db = Firestore.firestore()
db.collection("Users").document().collection("RechargeCoin")
.order(by: "date", descending: true)
.addSnapshotListener { (snapshot, error) in
I want to update the value in postID, but use: collectionGroup("RechargeCoin"), but the document cannot be updated, it shows: collectionGroup("RechargeCoin"), what should I do?
fireStoreDB.collectionGroup("RechargeCoin")
.document("\(String(describing: self.postArray[indexPath.row].postId))")
.updateData (userInfo as [String : Any], completion: {(error) in
})

As from your query you are not particular about any document in users collection and want only documents within RechargeCoin subcollection sounds like perfect job for Collection group queries using db.collectionGroup("RechargeCoin") as follows:
let db = Firestore.firestore()
.db.collectionGroup("RechargeCoin")
.order(by: "date", descending: true)
.getDocuments { (snapshot, error) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
Reference from this thread

Related

Async call blocking main thread when using DispatchGroup

I am trying to get documents from a FireStore database. I need these documents to be loaded before moving forward in my function. Here is the code for reference:
The view controller calling the FireStore service functions:
let service = FirestoreServices()
service.get(cottage: "test123456789") { model in
nextViewController.cottageModel = model!
self.present(nextViewController, animated:true, completion:nil)
}
The FireStore service method being called:
func get(cottage: String, completionHandler: #escaping (CottageTrip?) -> ()) {
//get a reference to the firestore
let db = Firestore.firestore()
//get the references to the collections
let cottageRef = db.collection("cottages").document(cottage)
//get the fields from the initial document and load them into the cottage model
cottageRef.getDocument { (document, error) in
if let document = document, document.exists {
//create the cottage model to return
let cottageModel: CottageTrip = CottageTrip()
//get the subcollections of this document
let attendeesCollection = cottageRef.collection("attendees")
//other collections
//here I get all info from initial document and store it in the model
let group = DispatchGroup()
print("here")
group.enter()
//get the attendees
DispatchQueue.global(qos: .userInitiated).async {
attendeesCollection.getDocuments() { (querySnapshot, err) in
print("here2")
if let err = err {
print("Error getting documents: \(err)")
} else {
//get data
}
group.leave()
}
}
print("after async call")
//wait here until the attendees list is built
group.wait()
print("after wait")
//create the cars
carsCollection.getDocuments() { (querySnapshot, err) in
print("in car collection get doc call")
if let err = err {
print("Error getting documents: \(err)")
} else {
//get car data
}
}
}
//this is where she should block until all previous get document operations complete
completionHandler(cottageModel)
} else {
print("Document does not exist")
completionHandler(nil)
}
}
}
I am realizing that the print("here2") never prints so it seems like it blocks on the group.wait(). I need to use group.wait() rather than a notify because I need this function to access subcollections and documents only after the attendees collection is loaded as I need these values for the subcollections and documents. I have read a lot of answers online and most people use group.wait() in this scenario but for some reason I can not get it to work for me without locking and freezing the application.
As algrid pointed out, you have a deadlock because you are waiting on the main thread, which Firestore needs to call its closures.
As a general rule, avoid calling wait and you will not deadlock. Use notify, and just call your closure inside that notify closure.
So, for example, assuming that you do not need the results from attendees in order to query the cars, you can just use a notify dispatch group pattern, e.g.
func get(cottage: String, completionHandler: #escaping (CottageTrip?) -> Void) {
let db = Firestore.firestore()
let cottageRef = db.collection("cottages").document(cottage)
cottageRef.getDocument { document, error in
guard let document = document, document.exists else {
print("Document does not exist")
completionHandler(nil)
return
}
let cottageModel = CottageTrip()
let attendeesCollection = cottageRef.collection("attendees")
let carsCollection = cottageRef.collection("cars")
let group = DispatchGroup()
group.enter()
attendeesCollection.getDocuments() { querySnapshot, err in
defer { group.leave() }
...
}
group.enter()
carsCollection.getDocuments() { querySnapshot, err in
defer { group.leave() }
...
}
group.notify(queue: .main) {
completionHandler(cottageModel)
}
}
}
Also, as an aside, but you do not have to dispatch anything to a global queue, as these methods are already asynchronous.
If you needed the result from one in order to initiate the next, you can just nest them. This will be slower (because you magnify the network latency effect), but also eliminates the need for the group at all:
func get(cottage: String, completionHandler: #escaping (CottageTrip?) -> Void) {
let db = Firestore.firestore()
let cottageRef = db.collection("cottages").document(cottage)
cottageRef.getDocument { document, error in
guard let document = document, document.exists else {
print("Document does not exist")
completionHandler(nil)
return
}
let cottageModel = CottageTrip()
let attendeesCollection = cottageRef.collection("attendees")
let carsCollection = cottageRef.collection("cars")
attendeesCollection.getDocuments() { querySnapshot, err in
...
carsCollection.getDocuments() { querySnapshot, err in
...
completionHandler(cottageModel)
}
}
}
}
Either way, I might be inclined to break this up into separate functions, as it is a little hairy, but the idea would be the same.

Cloud Firestore unable to retrieve document or field

I've used the sample code provided by the Firebase Documentation and it prints out the error message. I have no clue if the issue is within the code or within the structure of the database, as there are also sub-collections. In this case, I am trying to retrieve the "Home Title" field, however I heard that that's not possible (I may be wrong), so I'm trying to retrieve the "Sample Wedding" document, to no avail. This is my very first time programming a project in Swift and also using Firestore.
Here's my code:
let db = Firestore.firestore()
let docRef = db.collection("Weddings").document("Sample Wedding")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
Here's my database structure:
]
You can try it like this
let db = Firestore.firestore()
db.collection("Weddings").document("Sample Wedding").getDocument {
(documentSnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
print("Document data: \(documentSnapshot)")
if let title = documentSnapshot.get("Home Title") as? String {
print(title)
}
}
}

Firestore not returning query Swift 5 Xcode 11.3

I'm currently trying to develop an ios application using Firestore, and when querying the database, I'm getting no results, as neither the if/else block execute. I'm wondering what is going wrong here...
db.collection("users").whereField("uid", isEqualTo: uid).getDocuments() { (querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error.localizedDescription)")
} else {
for document in querySnapshot!.documents {
weight = document.data()["weight"]! as? Double
}
}
}
Database file structure
Update: I make a call to the database in an earlier method, and this properly returns the user's first name (when I add the weight, it also returns the correct value). But any subsequent calls fail to return anything. Hopefully that info helps.
I have the same Firestore structure like you, and this works for me:
func test() {
var accessLevel: Double?
let db = Firestore.firestore()
db.collection("users").whereField("uid", isEqualTo: UserApi.shared.CURRENT_USER_UID!).getDocuments() { (querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error.localizedDescription)")
} else {
for document in querySnapshot!.documents {
accessLevel = document.data()["accessLevel"]! as? Double
print(accessLevel!)
}
}
}
}
Current uid:
// Actual logged-in User
var CURRENT_USER_UID: String? {
if let currentUserUid = Auth.auth().currentUser?.uid {
return currentUserUid
}
return nil
}
Hope it helps.

Get document id From Firestore Swift

I am trying to get the document id from Firestore by executing a query like this:-
func updateStatusInFirestore() {
let orderid = saleOrder.first?.Orderid ?? ""
print(orderid)
let settings = db.settings
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings
self.db.collection("SaleOrders").whereField("orderid", isEqualTo: "\(orderid)").getDocuments { (snapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in snapshot!.documents {
self.documentid = document.documentID
print(self.documentid)
}
}
}
}
In which I am getting the order id from my model class and it is printing the value of order id but when I am trying to put it in whereField query it is not exectuing the query and I am not getting any result in my console.
If I use like this it is working
self.db.collection("SaleOrders").whereField("orderid", isEqualTo: "ji20190205091948").getDocuments
but when I use like this
let orderid = saleOrder.first?.Orderid ?? ""
self.db.collection("SaleOrders").whereField("orderid", isEqualTo: "\(orderid)").getDocuments
It is not working. What is wrong I am doing. Please help?
I Solved the problem. We just need to add one if condition to get the documentId of that particular collection from Firestore
for document in snapshot!.documents {
if document == document {
print(document.documentID)
}
}

How to process firestore query as i am getting snapshot result as FIRQuerySnapshot`

I am facing problem while processing firestore query as my code is here
let wallpaperRef = Firestore.firestore().collection("wallpaper").order(by: "noOfDownloads", descending: true)
wallpaperRef.getDocuments(completion: { (snap, error) in
if error == nil {
print(snap)
}
})
now the output of this query is this
Optional(<FIRQuerySnapshot: 0x600000070640>)
Optional(<FIRQuerySnapshot: 0x600000070640>)
Optional(<FIRQuerySnapshot: 0x6000000705c0>)
i want to take this querysnap and get data whatever is init to readable form
If you run a query against a collection, the result you get is a QuerySnapshot that contains (possibly) multiple documents. To get each document, you need to loop over the results. From the Firebase documentation on reading multiple documents:
db.collection("cities").whereField("capital", isEqualTo: true)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
So your code is jut missing the loop from that else block. Something like:
wallpaperRef.getDocuments(completion: { (snap, error) in
if error == nil {
print(snap)
} else {
for document in snap!.documents {
print("\(document.documentID) => \(document.data())")
}
}
})

Resources