Reputation: 893
I need to pull the record from cloudkit matching a string.
I have a User record type, with an email field. I have multiple records with the same email, but I can't get the predicate to get me the records.
I've tried all of these:
let predicate = NSPredicate(format: "email = '[email protected]'")
NSPredicate(format: "email == %@", argumentArray: [email])
NSPredicate(format: "email IN %@", [email])
NSPredicate(format: "email contains %@", email)
NSPredicate(format: "email = %@", email)
NSPredicate(format: "email == %@", email)
My query specifies the record type:
let query = CKQuery(recordType: "User", predicate: NSPredicate(format: "email == %@", email))
When I do a predicate with value: true, I get all records including the one I want.. I know for sure I have a User with that email, multiple in fact..
What am I missing?
Edit ..
let query = CKQuery(recordType: "User", predicate: NSPredicate(format: "email BEGINSWITH %@", email))
Does work and brings back records, but I want an exact match!
Upvotes: 3
Views: 3359
Reputation: 71
I had same issue and was able to resolve it by adding Queryable index on user field in my case. Note, after index was added I needed to write data again to CloudKit to be able to perform query.
Code for creation of predicate:
let user = "test-user"
let userPredicate = NSPredicate(format: "user == %@", user)
Upvotes: 7
Reputation: 166
I've been having this same issue with one of my apps. In my case, I needed to subscribe to a list of predicates where a lot of search criteria needed to be met but the search or filter predicate gave me the most trouble. I also tried:
let word1 = "Mac"
let predicate = NSPredicate(format: "Title CONTAINS %@", word1)
This worked but only when 'word1' was a single word with no spaces and 'Title' was a 'String List' in the cloud.
The clarification that I have come across in all my research is:
You need to use the term 'self' when you create a predicate and what that does is it searches all the fields that are a searchable string. Here is the information I got from Apple's Website.
Predicates support the following variable substitution strings:
Use %@ for value objects such as strings, numbers, and dates.
Use %K for the name of a field. This substitution variable indicates that the substituted string should be used to look up a field name.
With one exception, the CONTAINS operator can be used only to test list membership. The exception is when you use it to perform full-text searches in conjunction with the self key path. The self key path causes the server to look in searchable string-based fields for the specified token string. For example, a predicate string of @"self contains 'blue'" searches for the word “blue” in all fields marked for inclusion in full-text searches. You cannot use the self key path to search in fields whose type is not a string.
What I ended up doing, which there has to be a better way, is my 'Title' property is still a 'String List' in the cloud and in my code I made an array of all the words in my searchTerm and with each word in the searchTerm I made a separate NSPredicate and I used those as part of a NSCompoundPredicate. I then added the NSCompoundPredicate to my subscription and it worked. Here is my example:
var searchCriteria: [NSPredicate] = []
for word in searchTerm {
let predicate = NSPredicate(format: "self CONTAINS %@", word)
searchCriteria.append(predicate)
}
let p2 = NSPredicate(format: "Price > %d", minPrice)
let p3 = NSPredicate(format: "Price < %d", maxPrice)
let p4 = NSPredicate(format: "Category == %d", category)
searchCriteria.append(p2)
searchCriteria.append(p3)
searchCriteria.append(p4)
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: searchCriteria)
I hope this helps. There has to be a better way to do this and if anyone knows, please let me know cause I understand there isn't a lot of good explanations on how to do things with CloudKit.
Upvotes: 3