add componentsseparatedbystring into a predicate with core data - ios

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.

Related

Building a complex predicate to compare attribute string contains any string in Array

I have an entity name A and it has an attribute A.uid. Now I have an array of Strings containing global UIDs. Now any string in this array can be substring of A.uid. How to build a complex NSPredicate for NSFetchReuqest for this so that it gives me only those A objects which have this substring match from array of strings. I am assuming we can't use NSString operations inside [NSPredicate predicateWithFormat:].
I have tried using IN for this but I want to somehow figure out substring approach inside my SUBQUERY. Also I have to make a SUBQUERY otherwise use of IN is throwing error.
I don't have an Objective-C project handy, but this worked in Swift and should do the job for you (if I understand your question).
I ran this on a core data entity with a single attribute: name
NSArray *a = #[
#"123",
#"456",
];
NSString *searchString = [a componentsJoinedByString:#"|"];
NSString *format = #"(name MATCHES %#)";
NSString *pattern = [NSString stringWithFormat:#".*(%#).*", searchString];
NSPredicate *predicate = [NSPredicate predicateWithFormat:format, pattern];
My data consists of:
Joe123Smith
Bob456Smith
Dave789Smith
Steve764Smith
Tom12345Smith
Mike397456288Smith
123TimSmith
TomSmith456
and the returned matched set of records is:
Joe123Smith
Bob456Smith
Tom12345Smith
Mike397456288Smith
123TimSmith
TomSmith456
Edit
I just tested this on an Objective-C project and it works as expected.

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.

Escape nonbreaking space as argument in NSPredicate

I want to filter out empty records, but I am not able to remove the records which has no data but a series of space..
I have a Entity A with attribute "name" . I want to query all those objects of Entity A which has some text value for attribute name and not "series of space",In other words I need to incorporate this in the query -->
[name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet].length!=0
But all I could was check the length of string INCLUDING the whitespace which is not right.
I am using-->
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"name!=' ' or name.length!=0 "];
Your suggetions are welcome.
you can trim the string and check for the lenght of the string like this:
NSString *trimmedString = [aRecordString stringByTrimmingCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:#" "]]];
if (trimmedString.lenght > 0) {
// the string if valid or at least is not just a spaces string
}
else {
// the string is not valid or was just a spaces string
}
so if you want to apply this check in a predicate you can use a predicate with block:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
// do your checks here and return TRUE or FALSE if the ovject match your criteria
}];
If you're trying to remove objects where a specific string attribute contains only spaces, use a regex-based predicate, and then delete whatever objects you find.
A fetch with a predicate like this would find all of those objects:
NSPredicate *reqPredicate = [NSPredicate predicateWithFormat:#"attributeName matches ' +'"];
Once found, use -[NSManagedObjectContext deleteObject:] to delete the resulting objects.

NSPredicate predicateWithFormat:argumentArray: Only Evaluating First Argument

I'm having some trouble using NSPredicate predicateWithFormat:argumentArray:. In this example, serverIDList is array of strings. Results is an array of NSManagedObjects with an attribute named "flid" which is a string.
NSMutableString *predicateString = [[NSMutableString alloc] init];
[predicateString appendString:#"(flid IN %#)"];
[results filterUsingPredicate:[NSPredicate predicateWithFormat:predicateString argumentArray:serverIDList]];
The problem is that [NSPredicate predicateWithFormat:predicateString argumentArray:serverIDList] evaluates to "flid IN '2155'", which is only the first value of the array serverIDList. I can't seem to get the predicate to evaluate the entire array. Is there something missing here?
Thanks!
[NSPredicate predicateWithFormat:#"(flid IN %#)" argumentArray:serverIDList]
is equivalent to
[NSPredicate predicateWithFormat:#"(flid IN %#)", id1, id2, ..., idN]
where id1, ..., idN are the elements of the array serverIDList.
That should explain why only the first element is evaluated.
What you probably want is
[NSPredicate predicateWithFormat:#"(flid IN %#)", serverIDList]
Remark: I would recomment not to create predicates as strings first. The chances for
quoting or escaping errors are quite high. Use only predicateWithFormat with a
constant format string. If you have to combine predicates dynamically at runtime,
use NSCompoundPredicate.

Resources