CKQuery with NSPredicate fails when using “CONTAINS” operator

According to Apples Class Reference CKQuery, the operator "CONTAINS" is one of the suported operators. However, that doesn't seem to work. I have a recordtype called myRecord, and a record with filedname "name" type String. I try to fetch the record with two different predicates, one with "==" operator, and one with "CONTAINS" operator.


func getRecords(){ 
     let name = "John" 
     let Predicate1 = NSPredicate(format: "name == %@",name) 
     let Predicate2 = NSPredicate(format: "name CONTAINS %@",name) 
     let sort = NSSortDescriptor(key: "Date", ascending: false) 
     let query = CKQuery(recordType: "myRecord", predicate: Predicate1)
     //let query = CKQuery(recordType: "myRecord", predicate: Predicate2)    
     query.sortDescriptors = [sort] 

     let operation = CKQueryOperation(query: query) 
     operation.desiredKeys = ["name", "Date"] 

     operation.recordFetchedBlock = { (record) in 

     print(record["name"]) 
     operation.queryCompletionBlock = { [unowned self] (cursor, error) in 
     dispatch_async(dispatch_get_main_queue()) { 

     if error == nil 
     { print ("sucess") 
     } else { 
     print("couldn't fetch record error:\(error?.localizedDescription)") } 
          } 
     } 
     CKContainer.defaultContainer().publicCloudDatabase.addOperation(operation) 
}


Using Predicate1, outout is: Optional(John) sucess

Using Predicate2, outout is: couldn't fetch record error:Optional("Field \'name\' has a value type of STRING and cannot be queried using filter type LIST_CONTAINS")

Also using [c] to ignore casings gives a crash.

How do I use the operator "CONTAINS" correctly, and how do I ignore letter casings?

Replies

Read the document again. You are searching a text field. You are not doing a 'token search' and you are not doing an 'aggregate operation'.


https://developer.apple.com/library/prerelease/ios/documentation/CloudKit/Reference/CKQuery_class/

"For fields that contain string values, you can match the beginning portion of the string using the

BEGINSWITH
operator as shown in Listing 4. You cannot use other string comparison operators such as
CONTAINS
or
ENDSWITH
."

>You are searching a text field.


Technically, it's a sort, not a search, would typically involves a data source that has been previously indexed.

CONTAINS (IN, ANY) is only available for datasets, such as arrays since it's basically "Does this list CONTAIN this item?".


The example in CKQuery gives you an excellent idea of how it looks like.

NSPredicate predicate = nil;
predicate = [NSPredicate predicateWithFormat:@"ANY favoriteColors = 'red'"];
predicate = [NSPredicate predicateWithFormat:@"favoriteColors CONTAINS 'red'"];
predicate = [NSPredicate predicateWithFormat:@"'red' IN favoriteColors"];
predicate = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", @"favoriteColors", @"red"];

I had the same issue. What I wound up doing is creating a "filter" function which iterated through the CKRecords and removed records which did not match my search criteria. Here's the business part of that code.

guard var records = theRecords else {return nil}
for (index, record) in records.enumerated().reversed() {
    if let keyResult = record[keyWord] as? String {
        let resultString = keyResult.lowercased()
        if !resultString.contains(searchWord.lowercased()) {
            records.remove(at: index)
        }
    }
}