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".)
Related
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.
I am trying to search in CoreData for an object that matches both a recordId and a string name, but it doesn't always find the object.
For example, I an searching for an object with id 1000 and name "The Brown Family" (note the 2 spaces between "The" and "Brown").
If I use:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#") AND (name like[cd] %#)", recordId, name];
with recordId=1000 and name="The Brown Family", the fetch request returns nil.
If I use:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#"), recordId];
with recordId=1000, it finds the object. If I print the object's name property, I get "The Brown Family".
So the object is there with the correct id and name, but my fetchRequest fails.
What am I doing wrong?
You might need to enclose the value in single quotes...
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#) AND (name like[cd] '%#')", recordId, name];
Sorry but I realise what the problem is now! The name I was searching for had a trailing space after it. So I was looking for say "Toby " whereas "Toby" was stored in Coredata.
Sorry for wasting everyone's time.
i know that the question sounds wears.I couldn't find a better way to put it so i will take my time to explain the question i m struggling with.
I have an iPhone app that takes input from user.And i got a plist ( i will convert it to a online database soon) What i currently do is this. I compare my input string with ingredients part of items in my plist.
This is the plist format
<array>
<dict>
<key>category</key>
<string>desert</string>
<key>numberOfPerson</key>
<string>3</string>
<key>recipeImage</key>
<string>asd.jpg</string>
<key>time</key>
<string>15</string>
<key>recipeName</key>
<string>Puding</string>
<key>recipeDetail</key>
i compare the input with recipeIngredients.But what my codes do is not what i need.If the comparison turns true i just list every item from my plist that contain the input ingredients.I can filter through selected recipes but what i want is this: Unless there is a full match up with input and ingredients i do not want to show it.
The problem is this. I got my recipe ingredients like this format 1 spoon of sugar, 1 spoon of salt, 100g chicken.
The user enter inputs like - salt , sugar. chicken so i can not fully compare it.It will never be the same so i can not show anything.
How can i accomplish this.
i m open for any kind of suggestions.
This is how i compare
results = [arrayOfPlist filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSDictionary *_dataRow = (NSDictionary *)evaluatedObject;
return ([[[_dataRow valueForKey:#"recipeIngredients"] lowercaseString] rangeOfString:[searchText lowercaseString]].location != NSNotFound);
}]];
where searchText is my input.
First of all, you'll never know if there is a typo in user input.
But what you can do is before you compare two strings, you can do a little bit trimming for a given character set.
There is a method in NSString class called :
- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set
If you want to get rid of . or - characters, you need to specify them in your character set. Than, you can compare two strings.
Using -[NSPredicate predicateWithFormat:] you can do database-esque string comparisons. For instance, you could try
[NSPredicate predicateWithFormat:#"recipeIngredients CONTAINS[cd] %#", searchText]
Check out https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html the section called "String Comparisons"
EDIT: if the user will be searching multiple things at once, like "chicken, noodle," you can be a little more fancy and do:
NSArray *tokens = [[searchText componentsSeparatedByCharactersInSet:NSCharacterSet.alphanumericCharacterSet.invertedSet] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"length > 0"];
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"recipeIngredient CONTAINS[cd] (ANY %#)", tokens]
You should split up the searchText into an array by using -componentsSeparatedByString:#",", and then loop through the array to see if the recipeIngredients contains any of the ingredients in the searchText array. In order to work out if the query contains every single ingredient, you can create an integer inside of the block and increment it everytime you have a match. If the number of matches is equal to the number of ingredients, then you can go from there.
The code below builds up a predicate that boils down to "ingredients contains sugar and ingredients contains chocolate"
NSArray* recipes = #[
#{#"recipeIngredients": #"sugar flour chocolate"},
#{#"recipeIngredients": #"sugar chocolate"},
#{#"recipeIngredients": #"flour chocolate"},
#{#"recipeIngredients": #"chocolate"},
];
NSString* search = #"sugar, chocolate";
// split the ingredients we have into an array of strings separated by ',' or ' '
NSArray* haves = [search componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#", "]];
// Build a list of recipeIngredients CONTAINS have
NSMutableArray* ands = [NSMutableArray new];
for(NSString* have in haves)
{
if(have.length > 0)
{
[ands addObject:[NSPredicate predicateWithFormat:#"recipeIngredients CONTAINS[cd] %#", have]];
}
}
// String all the haves into a single long ... AND ... AND ... predicate
NSPredicate* predicate = [NSCompoundPredicate andPredicateWithSubpredicates:ands];
// Apply the predicate
NSArray* filtered = [recipes filteredArrayUsingPredicate:predicate];
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
I have 3 NSManagedObjets; Person, Stuff, and Collection.
I want to use a NSPredicate to get a list of all Collections that ThePerson has.
Example: Scott has objectA and objectB which are in collection Letters and object1 which is in collection Numbers.
I want to be able to do a fetch request and get back collection Letters and Numbers.
I tried:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY stuffs.persons == %#", person];
And:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(stuffs, $s, ANY $s.persons == %#)", scott];
Any suggestions?
Your SUBQUERY syntax is wrong (for a full explanation, see this answer or this answer). It should be something like:
SUBQUERY(stuffs, $s, ANY $s.persons == %#).#count > 0
Since it seems that you already have a reference to a ThePerson object, you don't need to do a fetch or use a predicate. You can traverse the relationships you've declared to get the collections. You can get all of the Collections that ThePerson has by using:
NSSet *collections = [person valueForKeyPath:#"stuffs.collections"];