JDM
JDM

Reputation: 893

NSPredicate matching string for Cloudkit

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

Answers (2)

vanjakom
vanjakom

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

avanalfen
avanalfen

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

Related Questions