NSArray as parameter in Core Data fetchRequest - ios

I have database of about 10.000 entities and dynamic NSArray of 50 NSString elements. Would like to check if each of those elements exist in database and create new array of ones that exist. I don't need to return whole entities, just those NSString titles ( which are the same as in NSString array)
NSPredicate should compare entity.title to NSString element with EXACT match.
What is the best and processor/memory efficient way to do it?

I think that you should use the 'in' operation in your predicate to get your result. This lets you leverage the database to perform the comparison, instead of bringing back all of the 10,000 records to compare yourself. If you take this approach, your code could look like this:
// Assuming that arrayName is your existing array of values to match, that
// EntityName is the object in CoreData that you’re looking at, and context
// is your moc
var newArray: [String] = []
let fetchRequest = NSFetchRequest<EntityName>(entityName: "EntityName")
fetchRequest.predicate = NSPredicate(format: "title in %#", arrayName)
do {
result = try context.fetch(fetchRequest)
for element in result {
newArray.append(element.title)
}
} catch {
… manage any errors …
}
Note - I'm targeting Swift 3.0 compatible code - not sure if swift was what you're after.

Related

Use CONTAINS or ANY in CloudKit predicate with an array of comparison

I tried to use NSCompoundPredicate(orPredicateWithSubpredicates:) with CloudKit NSPredicate but then I read on Apple's documentation that OR comparison predicates aren't supported in CloudKit so I hit a road-block with this.
I have an array of CKReferences that I need to see if a Record-type of Reference list contains those references.
I'm struggling on how to assemble the predicate itself , because I'm trying to avoid nested-queries in the completionBlock.
let's say I have the following array of references:
let refs = [CKReference]() // in my case the array isn't empty
I tried the following but it didn't worked, because somehow it only looks for the first object of the array, and not the whole array.
let predicate = NSPredicate(format: "tableName CONTAINS %#", argumentArray: refs)
Here if I print the predicate it prints:
tableName CONTAINS CKReference: 0x600000229c40; 20B54862-46CC-405F-BAE8-0DC8D3A52F78:(_defaultZone:defaultOwner)>
As you can see, it only looks for the first object in the array.
It may work if I use the ANY operator in the predicate, something like:
let predicate = NSPredicate(format: "ANY { '%#', '%#' } = tableName", args: refs[0], refs[1])
But my problem here is how can I build that predicate, since the refs array is dynamic and I don't know how many objects it may contain , and by that I don't know how to build the predicate args accessing the [0], [1], ... of the refs array.
Do you have any workaround with this? Or a best way to approach this issue?
Thank you.
EDIT
I figure out a way to solve this issue, but I don't know if that's the most efficient one, so I'm still opened to answers and opinions.
Here's my temporary solution:
for (i, reference) in refs.enumerated() {
let predicate = NSPredicate(format: "tableName CONTAINS %#", reference)
// CKQuery
// CKQueryOperation
// Database.add(CKQueryOperation)
if i == refs.count - 1 {
// UPDATE UI
}
}
NSMutableArray * tagsReferencesArray = [[NSMutableArray alloc] init];
[tagsReferencesArray addObject:tag100_Reference];
[tagsReferencesArray addObject:tag300_Reference];
[tagsReferencesArray addObject:tag200_Reference];
predicate= [NSPredicate predicateWithFormat:#"ANY %# in field_TagsReferenceList ", tagsReferencesArray];

Core Data Filter Predicate With An Array Swift

I am trying to pull objects out of my core data store by passing in an array of strings, and pulling only the objects that have a category matching what's in the array.
I have been able to get this code to work, except that it only uses the first item in the array, and won't iterate through the array and match the rest of the items.
This is the code that works for that. I am using the NSPredicate overload that accepts and array.
func filterTopicCategories() {
fetchController.topicFetchRequest.predicate = NSPredicate(format: "topicCategory == %#", argumentArray: selectedCategories)
topicsToSelectFrom = fetchController.fetchTopics()
}
I've poured through that Apple docs on predicates and all that, and can't seem to quite figure it out. I've spent a few hours searching around google as well. I am not sure if I am just not understanding something correctly, or if I am just doing it completely wrong, I am not sure. Any help would be greatly appreciated.
Thanks
The parameter argumentArray is for an array of values to replace the placeholders like %# in the format string.
You are looking for the IN operator:
IN
Equivalent to an SQL IN operation, the left-hand side must appear
in the collection specified by the right-hand side. For example, name IN { 'Ben', 'Melissa', 'Nick' }. The collection may be an array, a
set, or a dictionary — in the case of a dictionary, its values are used.
In Objective-C, you could create a IN predicate as shown in the
following example:
NSPredicate *inPredicate = [NSPredicate predicateWithFormat: #"attribute IN %#", aCollection];
where aCollection may be an instance of NSArray, NSSet,
NSDictionary, or of any of the corresponding mutable classes.
So if topicCategory is a string write
fetchController.topicFetchRequest.predicate = NSPredicate(format: "topicCategory IN %#", selectedCategories)
Okay, so I finally stumbled onto this question Swift Core Data Predicate IN Clause that mentioned removing the argumentArray label in the overload. I tried that and then changed my predicateFormat as well. So now it looks like this
func filterTopicCategories() {
fetchController.topicFetchRequest.predicate = NSPredicate(format: "ANY topicCategory IN %#", selectedCategories)
topicsToSelectFrom = fetchController.fetchTopics()
}
and it seems to work now. Not sure if this is a bug, because the autocomplete in Xcode puts that label there, so, weird.
Anyway, hope this helps someone struggling with the same issue.
Thanks.
this worked for me:
`
let isWatchLaterPredicate = NSPredicate(format: "isWatchLater == YES")
let managedContext = appDelegate.managedObjectContext
let fetchRequestWatchLater = NSFetchRequest<NSManagedObject>(entityName: "WatchList")
fetchRequestWatchLater.predicate = isWatchLaterPredicate
print(fetchRequestWatchLater)
do {
watchList = try managedContext.fetch(fetchRequestWatchLater)
print("watch List Items \(isWatchLaterPredicate)")
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
`

Using Kii Query Result

I am running a Kii Query that returns the expected number of results. However the results array contains object formatted as follow
"<KiiObject: 0x130471ae0>"
this is the output from
NSLog(#"%#",results);
I am confident that the Query is working correctly as i can add and remove objects from the bucket and the number of results in the array changes according, i just don't know how to take the results and get the corresponding object.
I have gone over everything in the Kii Doc's
link to Kii Docs
The result is to short to be the object id(uuid string) and i can't find any other reference in the docs that makes sense.
You can refer to bellow snippet
NSError *error = nil;
// Build "all" query
KiiQuery *allQuery = [KiiQuery queryWithClause:nil];
// Create an array to store all the results in
NSMutableArray *allResults = [NSMutableArray array];
// Create a placeholder for any paginated queries
KiiQuery *nextQuery;
// Get an array of KiiObjects by querying the bucket
NSArray *results = [bucket executeQuerySynchronous:allQuery
withError:&error
andNext:&nextQuery];
if (error != nil) {
// Error handling
return;
}
//obtain single KiiObject
KiiObject* firstObject = allResults.firstObject; // now you should get all the object properties
NSLog(#"MaxScore : %#",[firstObject getObjectForKey:#"maxScore"]); //i.e to get "maxScore" value
Below is the links for querying KiiObjects.
http://docs.kii.com/en/guides/ios/managing-data/object-storages/querying/

Getting distinct rows from Realm table in iOS

I am using Realm database for iOS application where i have a use case in which i want to filter result set by distinct values for a particular field. This field is not a primary key of the realm table.
I was not able to construct query for that.
Sample query :
RLMResults *allFiles = [FileRLMObject objectsInRealm:realmObject where:#"colA == %#", #"test1"];
FileRLMObject is a subclass of RLMObject from realm library
here table contains one column with name colB. While getting allFiles results, i want to get rows which are having distinct colB values.
Any suggestions how i can achieve this?
Realm doesn't support distinct queries yet. You can subscribe issue #1103 to track progress on that.
As a workaround, you could query for all values for colB first and then select objects for each value of it, as seen below:
NSArray *values = [FileRLMObject.allObjects valueForKey:"type"];
NSSet *distinctValues = [NSSet setWithArray:values];
NSMutableArray *allFiles = [NSMutableArray new];
for (NSString *colB in distinctValues) {
// This takes the firstObject.
// You might want to modify the sort order to make sure
// you get a certain object in case that there may exist
// multiple objects per distinct value.
FileRLMObject *object = [FileRLMObject objectsWhere:#"colB == ?", colB].firstObject;
[allFiles appendObject:object];
}

NSPredicate from Core Data selecting by Object ID (and potentially summing)

I'm finding my way to the advanced part of core data. I know it is not SQL, and there are limitations, however, how would I translate the code below to a NSPredicate to be applied in a fetch request?
Product* p = self.product; //this is a managed object
double vol=0;
for (PlanningItem* pi in self.planitems) {
if (pi.product==p)
vol+=pi.volume;
I want to fetch all plan items that have p as their product.
Next I want to sum all the volumes of that set.
How do I do 1 in a fetch request with a NSPredicate?
Can i do 2 at the same time?
I'm asking for the string for the NSPredicate. I am capable of building the Fetchrequest myself.
Tx!
// Create the predicate
NSPredicate *productPredicate =
[NSPredicate predicateWithFormat:#"(product == %#)", product];
// Apply the predicate to your FetchRequest
[fetchRequest setPredicate:productPredicate];

Resources