According to the Firestore documentation, it is possible to create a Query using .filter(using: NSPredicate). I tried this using the following code (Swift 5, iOS 12.4, Xcode 11):
let predCondition = "title BEGINSWITH %#"
let searchKeyText = "Uxbridge"
let myPredicate = NSPredicate(format:predCondition, searchKeyText.lowercased())
let mapsRef = dbFS.collection("mapDetails")
let query = mapsRef.filter(using:myPredicate)
query.getDocuments()
{ (querySnapshot, err) in
if let snap = querySnapshot, snap.isEmpty
{
print("Document not found")
}
else
{
if let err = err
{
print("Error getting documents: \(err)")
}
else
{
for document in querySnapshot!.documents
{
print("\(document.documentID) => \(document.data())")
}
}
}
}
This compiled but resulted in an exception at run time:
*** Terminating app due to uncaught exception 'FIRInvalidArgumentException', reason: 'Invalid query. Operator type 8 is not supported.'
It seems that the type of predicate "title BEGINSWITH %#" is not supported. Does anyone know what types are available? I could not see anything in the documentation but if there is something I missed, I would appreciate it if someone would direct me to it. Also is there any possibility that BEGINSWITH, etc. may be supported in the near future? Thx. RB
Related
In Xcode 13 beta for iOS 15, I am receiving a message that perform(_:inZoneWith:completionHandler:) (CloudKit) is deprecated in iOS 15 and renamed to fetchRecords(matching:inZoneWith:desiredKeys:resultsLimit:completionHandler:) However...
The Apple Docs website does not declare this method as deprecated: https://developer.apple.com/documentation/cloudkit/ckdatabase/1449127-perform
Apple is showing other deprecations for iOS 15 (another method): https://developer.apple.com/documentation/cloudkit/ckdatabase/3794331-records/
fetchRecords(matching:inZoneWith:desiredKeys:resultsLimit:completionHandler:) does not seem to exist.. yet.. (Value of type 'CKDatabase' has no member 'fetchRecords')
So, is this just an incorrect message because its beta? Should I worry about rewriting a function that uses perform(_:inZoneWith:completionHandler:)?
Here is my function, I've tried to adapt it to fetchRecords, but it does not exist. I tried adapting it to fetch(withQuery:completionHandler: but I'm kind of lost getting it to work..
(This function just deletes records from the iCloud private database):
let container = CKContainer(identifier: "MyContainerNameHere")
let recordType = "DBName"
//delete all saved icloud records
let query = CKQuery(recordType: recordType, predicate: NSPredicate(value: true))
container.privateCloudDatabase.perform(query, inZoneWith: nil) { (rec, err) in
if let err = err {
print(err.localizedDescription)
completion(.failure(err))
return
}
guard let rec = rec else {
completion(.failure(CloudKitHelperError.castFailure))
return
}
for record in rec {
container.privateCloudDatabase.delete(withRecordID: record.recordID) { (recordId, err) in
if let err = err {
print(err.localizedDescription)
completion(.failure(err))
return
}
guard recordId != nil else {
completion(.failure(CloudKitHelperError.recordIDFailure))
return
}
}
}
}
Any insight appreciated..
Thx
Update
I will say, that yes, this seems to be an error or at least a premature message, however, after rewriting the code for async/await, it is much cleaner and easier to read. For those struggling to figure this out, here is an example of the code above converted to Async/Await:
#MainActor func newDeleteCloudKit() async throws {
let container = CKContainer(identifier: "MyContainerNameHere")
let recordType = "DBName"
let query = CKQuery(recordType: recordType, predicate: NSPredicate(value: true))
let result = try await container.privateCloudDatabase.records(matching: query)
for record in result.0 {
try await container.privateCloudDatabase.deleteRecord(withID: record.0)
}
}
I'm in beta 5 and I still get this warning, but the method hasn't been implemented, so it looks like they are not deprecating the old one and just forgot to remove the warning. We should have the final version of Xcode in a few days.
UPDATE: It looks like the made a mistake. The new method is not called fetchedRecords(), it is called records() https://developer.apple.com/documentation/cloudkit/ckdatabase/3856524-records
I am trying to get the three most recent documents from my collection group userPosts using the following database structure and query:
-posts
-{userID}
-userPosts
-{documentID}
-postTime(Field)
Query:
postQuery = Firestore.firestore()
.collectionGroup("userPosts")
.order(by: "postTime", descending: true)
.limit(to: 3)
function used to query Firestore:
func loadPosts() {
postQuery.getDocuments{ [weak self](querySnapshot, error) in
self!.q.async{
var postsTemp = self?.postArray
for doc in querySnapshot!.documents{
self?.documents += [doc]
let post = self!.createPost(doc)
if(!self!.postArray.contains(post)){
postsTemp?.insert(post, at: 0)
}
DispatchQueue.main.async {
self!.postArray = postsTemp!
self!.tableView.reloadData()
}
}
}
}
}
However when I run this I get an error due to the fact that querySnapshot is nil. I am not sure why this happens since when I change descending to false I get a result but in the opposite order that I want. I have a feeling it has something to do with my query but am not sure where I went wrong.
The getDocuments callback gets called with two values (querySnapshot and `error), only one of which will have a value.
You're ignoring the error and assuming that querySnapshot has a value, which not only leads to the error you get, but also hides the likely cause.
I recommend following the pattern used in this example from the Firestore documentation on getting 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())")
}
}
}
By logging the error you can see what went wrong with your getDocuments() call.
I'm trying to check if a certain collection exists in my Firestore database, and here is my code for doing so:
let db = Firestore.firestore()
db.collection(pickedClass).getDocuments { (snapshot, error) in
if error == nil && snapshot != nil {
if snapshot!.documents.count > 0 {
for document in snapshot!.documents {
let documentData = document.data()
let info = documentData["info"] as! [String: Any]
output.append(object)
}
self.performSegue(withIdentifier: "showTutors", sender: output)
} else {
self.createAlert(title: "No Tutors Found", message: "Sorry, there are no tutors for this class", buttonMsg: "Okay")
}
}
}
The exception I get from running this apparently comes from the second line db.collection(pickedClass).getDocuments, and is as follows:
*** Terminating app due to uncaught exception 'FIRInvalidArgumentException', reason: 'Invalid collection reference. Collection references must have an odd number of segments, but has 0'
terminating with uncaught exception of type NSException
The bizarre thing is that most times this isn't an issue and the user sees the alert when the collection doesn't exist, but sometimes this happens. I never faced this issue until today, and I've been running this database and this snippet of code for over 2 months now.
Would really appreciate any help!
Hi, I'm implementing FireStore in first time as I study I found this
answer you can use this below mentioned code.
Firestore.firestore().collection("YOUR_COLLECTION_NAME_HERE")
.document("INSIDE_YOUR_COLLECTION_USE_DOCUMENT_ID_HERE_WHICH_YOU_WANT_TO_CHECK")
.getDocument { (document, error) in
debugPrint(document?.exists)
if document?.exists ?? false {
// EXIST
} else {
// NOT-EXIST
}
}
I have below code to get data from my firebase database
db.collection("users").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
print("starting name display")
for document in (querySnapshot?.documents)! {
let documentUserId = document.get("uid") as?String
let temp = document.data()["displayName"]
print(temp)
}
}
}
The print statement displays as optional("test name")
Why am i keep getting optional in my string. Same displays on the screen as well.
You need to un-wrap because it's an Optional. Means it could have a value or it could not have a value. So this is one method to handle it:
let temp = document.data()["displayName"] ?? ""
print(temp)
You could also use if let or guard let statements if you need to handle the cases where the value is actually empty.
Note: Take a look at the basics of swift. There is a separate section for Optionals.
I'm trying to develop an app that provide User sign up and within the UI I want to query if the email is exists or not.
The problem is since I change from swift 2 to swift 3 I got these errors
var query = PFObject(className:"User")
query.whereKey("email", equalTo: email)
query.findObjectsInBackground {
(objects, error) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects {
for object in objects {
print(object.objectId)
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
/Users/**************/SignUpSenderViewController.swift:49:9:
Value of type 'PFObject' has no member 'whereKey'
/Users/i*************/SignUpSenderViewController.swift:50:9:
Value of type 'PFObject' has no member 'findObjectsInBackground'
any suggestion to solve this challenge ?
I dont know what documentation you checked but the query has to be done this way...
let query = PFQuery(className:"_User")