NSPredicate with dynamic key and value - ios

I am trying to create a function that searches through my core data stack and return the amount of messages for a desired key/value.
Here is my code:
NSFetchRequest *messagesCountRequest = [NSFetchRequest fetchRequestWithEntityName:#"Message"];
NSEntityDescription *messageCountModel = [NSEntityDescription entityForName:#"Message" inManagedObjectContext:_mainManagedObjectContext];
[messagesCountRequest setEntity:messageCountModel];
NSPredicate *messageCountPredicate = [NSPredicate predicateWithFormat:#"%# == %#", key, value];
[messagesCountRequest setPredicate:messageCountPredicate];
count = (int)[_mainManagedObjectContext countForFetchRequest:messagesCountRequest error:nil];
The problem is that it returns 0 every time. I have located the source of the problem. When have a static key, the predicate looks like this.
key == "value"
When I pass through a dynamic key, it looks like this
"key" == "value"
So the problem appears to be the first set of double quotes around the key that is placed by passing a NSString to the predicate. How would I fix this?
EDIT: For clarity, I need it to be like the first case, that is the one that works.

To substitute a key in the predicate string, you have to use %K, not %#:
[NSPredicate predicateWithFormat:#"%K == %#", key, value];
From the Predicate Format String Syntax documentation:
%# is a var arg substitution for an object value—often a string, number, or date.
%K is a var arg substitution for a key path.

let predicate = NSPredicate(format: "SELF[%#] CONTAINS %#",key,value)
This worked for me

Related

How to set predicate for a string attribute holding integer value in core data

How to set predicate for a string attribute holding integer value in core data to get the in-between values in integer.
I am using compound predicate for multiple conditions and a piece of code follows..
NSPredicate *categoryPredicate = [NSPredicate predicateWithFormat: #"rating >= %# AND rating <= %#",ratingFrom.text,ratingTo.text];
[compoundPredicateArray addObject: categoryPredicate ];
"rating" attribute is of type string in database. I need to get the rating between the given range in the ratingFrom & ratingTo textfields.
"1" to "10" should fetch all ratings in between 1 to 10.how can I achieve this, without changing the attribute type to number.
Any help appreciated..Thanks
i am not confirm but try this
convert your values in NSString and put this code
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"string CONTAINS[c] %#",searchText];
Ideally you should change this attribute to be a number rather than a string. But if that's not possible, the following should force CoreData (or rather SQLite) to treat it as a number:
NSPredicate *categoryPredicate = [NSPredicate predicateWithFormat: #"add:to:(rating,0) >= %d AND add:to:(rating,0) <= %d",ratingFrom.text.intValue,ratingTo.text.intValue];
you can try BETWEEN expression:
BETWEEN The left-hand expression is between, or equal to either of,
the values specified in the right-hand side. The right-hand side is a
two value array (an array is required to specify order) giving upper
and lower bounds. For example, 1 BETWEEN { 0 , 33 }, or $INPUT BETWEEN
{ $LOWER, $UPPER }. In Objective-C, you could create a BETWEEN
predicate as shown in the following example:
So your code should look like this:
NSPredicate *betweenPredicate =
[NSPredicate predicateWithFormat: #"rating BETWEEN %#", #[ratingFrom, ratingTo]];
ratingFrom, ratingTo should be NSNumber instances if rating is NSNumber.

add componentsseparatedbystring into a predicate with core data

i have a String stored in an Entity (core data) i want to use an NSFetchedResultsController to get data.
string format: abc,ba,x,s,d. this is an array of IDs saved as string.
i want to get only entities that contains at least an IDs in that string.
the problem is if i use CONTAIN in the predicate and search for "a" i will get a wrong result.
could you please tel me if it's possible to add something like "componentsseparatedbystring" in a predicate so i can iterate and use "in"in the result or if there's an other solution, thanks.
You can use the "MATCHES" operator in a predicate, which does a
regular expression match:
NSString *searchID = #"a";
NSString *pattern = [NSString stringWithFormat:#"(^|.*,)%#(,.*|$)",
[NSRegularExpression escapedPatternForString:searchID]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ID MATCHES %#", pattern];
The pattern (^|.*,)TERM(,.*|$) searches for TERM which is preceded
by either the start of the string or a comma, and followed by the
end of the string or another comma.
First convert your array of ID's into an NSArray:
NSArray *arrayOfIds = [stringOfIds componentsSeparatedByString:#","];
Then use an IN predicate on your fetch:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ID IN %#", arrayOfIds];
this assumes your database column is called "ID", and your comma-separated string of ID's is stringOfIds.
finally i will use a dirty solution: we have 4 possibilities:
string format= a
string format= a,..
string format= ..,a
string format= ..,a,..
so the predicate could be:
[NSPredicate predicateWithFormat:#"(ID LIKE %# OR
ID CONTAINS %# OR
ID CONTAINS %# OR
ID ENDSWITH %#)",
searchedID,
[NSString stringWithFormat:#"%#,", searchedID],
[NSString stringWithFormat:#",%#", searchedID],
[NSString stringWithFormat:#",%#,", searchedID]]
but this is a dirty solution, i really want something cleaner.

NSPredicate and BEGINSWITH with CloudKit : Field value type mismatch

I have a table "Store" with the attributes "name" of type String (indexes checked for sort query and search).
I want to execute a SQL like query to find all stores with name beginning with a substring.
So I tried this predicate :
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY name BEGINSWITH %#",substring];
CKQuery *query = [[CKQuery alloc]initWithRecordType:#"Store" predicate:pred];
CKQueryOperation *queryOperation = [[CKQueryOperation alloc] initWithQuery:query];
queryOperation.desiredKeys = #[#"name",#"category"];
NSMutableArray *results = [[NSMutableArray alloc] init];
queryOperation.recordFetchedBlock = ^(CKRecord *record) {
[results addObject:record];
};
queryOperation.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error) {
//my own code
}
[publicDatabase addOperation:queryOperation];
I have this error :
<CKError 0x1887a540: "Invalid Arguments" (12/1009); "Field value type mismatch in query predicate for field 'name'"> for query : <CKQuery: 0x18882650; recordType=Store, predicate=ANY name BEGINSWITH "mysubstring">
My guess is that you need to get rid of the "ANY".
The ANY and SOME aggregate operators may be combined with the IN and
CONTAINS operators to perform list membership tests.
So ANY is for lists (Arrays). Since 'name' is a String, it is not a list, hence the mismatch error: "Field value type mismatch in query predicate for field 'name'"
Wild guess...try:
[NSPredicate predicateWithFormat:#"ANY {'name','category'} BEGINSWITH %#",substring];
That may be an incorrect reversal of key/value but it might work.
A completely different approach would be to create a third field called "nameAndCategory", append the two strings and add them to the field. Then figure out how to do the full text search (tokenized string search) with the predicate:
[NSPredicate predicateWithFormat:#"self contains '%#'",substring];
or
[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"self contains '%#'",substring];
But perhaps the only sure approach is to do two searches and combine the results.

NSPredicate Format String with unexpected result

I am learning NSPredicate and I have an example with problem.
NSArray * array = #[#{#"name":#"KudoCC"}, #{#"name":#"123"}] ;
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"name == '%#'", #123] ;
NSArray * result = [array filteredArrayUsingPredicate:predicate] ;
The parameter here is #123, it is NSNumber type. I think it works the same as #"name == '123'", but the result is nil, which I expected as #{#"name":#"123"}.
Can somebody tell me why? Thank you in advance.
The document here said,
If you use variable substitution using %# (such as firstName like %#), the quotation marks are added for you automatically.
Quotation marks should be avoided in common cases. If you use something like #"%K == '%#'", you are actually comparing the key with #"%#". Only if you have an array like #[#{#"%#": #"KudoCC"}], you need this way.

NSPredicate predicateWithFormat passing in name of attribute

Simple question regarding NSPredicate's. I'm trying to construct my predicate with "passed in" values like so :
NSPredicate* currentPredicate = [NSPredicate predicateWithFormat:#"%# == %#",key,[changesDict valueForKey:#"Id"] ];
However, I haven't been able to get this to work correctly. If I insert the actual value I pass through it does work though. So this works :
NSPredicate* currentPredicate = [NSPredicate predicateWithFormat:#"contactId == %#",[changesDict valueForKey:#"Id"] ];
(Notice i inserted contactId as opposed to the previous example where I pass a string by the same name)
To troubleshoot I NSLogged the two predicates looking at their descriptions and they were different. I'll show them below.
This is the working one
2013-01-17 10:29:25.513 TestingCoreData[1776:3b03] contactId == "5878"
This is the non working one
2013-01-17 10:29:25.513 TestingCoreData[1776:3b03] "contactId" == "5878"
So I can kind of see that it's inserting a string where I really just want the name of the attribute that i'll later be using in the fetch request. But is there any way to accomplish this by passing in values?
For keys or key paths, you have to use the %K format:
[NSPredicate predicateWithFormat:#"%K == %#", key, [changesDict valueForKey:#"Id"]];
(See Parser Basics in the "Predicate Programming Guide".)

Resources