Combining 2 values into a NSPredicate - ios

I'm trying to do a fetch request that checks for 2 things.
Here is my Data:
Person - entity
Statement - entity
The Person entity has a relationship to statements as To Many. The statement entity has an attribute called amountOwed. This is the property I want to check in the predicate.
EDIT
What I am trying to do is this.
Check all of my Persons entities for a name, lets say Bob.
Once I find the Bob entity I want to check all of his Statement entities for an attribute called amountOwed and see if it's greater or less then 0.
Check for a name in the Person Entity. When that name matches, use that entity.
Check if the amountOwed in a Statement entity is greater or less then 0.
This is what I have been trying to get to work.
let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
fetchRequest.predicate = NSPredicate(format:"name == %# AND #statement.amountOwed >= 0", personName))
let sort = NSSortDescriptor(key: #keyPath(Person.name), ascending: true)
fetchRequest.sortDescriptors = [sort]
positiveFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil)
do {
try positiveFetchedResultsController.performFetch()
} catch let error as NSError{
print("Fetching error: \(error), \(error.userInfo)")
}
I am getting this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'
I found the AND method here: using AND link
Edit

You should build your FRC to fetch Statement objects, not Person objects:
let fetchRequest: NSFetchRequest<Statement> = Statement.fetchRequest()
Assuming the statement relationship has an inverse (to-one) relationship named person, then you can use the following predicate to ensure you fetch only the statements with a positive amountOwed relating to a person with a given name:
fetchRequest.predicate = NSPredicate(format:"person.name == %# AND amountOwed >= 0", personName)
(and similarly for the negative amountOwed). Specify sort descriptors to get whatever sort order you wish. Your FRCs' fetchedObjects arrays will then contain Statement objects which you can use to populate the table view: the positive FRC for section 0 and negative FRC for section 1 (or vice versa).
NB. because you are fetching the Statement objects, it is possible to achieve what you want with just one FRC - but only if you are happy with the statements being sorted by amountOwed (ascending or descending). If you wish to do this, I can provide further detail.

Try this:
NSPredicate(format:"name == %# AND statement.#amountOwed >= 0", personName)
The AND has to be part of the string as the example you attached...

Related

Sorting NSFetchedResultsController items alphabetically but prioritize specific items in Swift and Coredata

I have a method that will fetch a batch of categories from persistent storage. I have added a sort descriptor that sorts the results alphabetically by name (attribute), which works perfectly. But I have 1 item that I would like to show up on top of the list which is "Uncategorized" and another one that I want to show at the bottom of the list which is "Other category". Can anyone help me on how I can pull this off?
What I've tried so far is add another sort descriptor to sort the items by "priority". Priority is an Int16 attribute in the Categories entity. But that didn't achieve what I wanted.
Here's the code to the method.
private func fetchCategories(predicate: NSPredicate, sortDescriptors: [NSSortDescriptor]) -> NSFetchedResultsController<Category> {
let fetchedResultsController: NSFetchedResultsController<Category>
let fetchRequest: NSFetchRequest<Category> = Category.fetchRequest()
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors
//fetch
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
do {
try fetchedResultsController.performFetch()
return fetchedResultsController
} catch {
debug.log(error.localizedDescription)
}
return fetchedResultsController
}
And here's the code calling that method:
func categories(ofType type: TransactionType) -> NSFetchedResultsController<Category> {
let predicate = NSPredicate(format: "tType == %# || tType == \(TransactionType.none.rawValue)", "\(type.rawValue)")
let nameSort = NSSortDescriptor(key: "name", ascending: true)
let fetchedCategories = fetchCategories(predicate: predicate, sortDescriptors: [nameSort])
return fetchedCategories
}
Update:
The priority + name sort solution did not work for me because I think the alphabetical takes precedence. Here's an example case.
Category name -> Priority
Travel -> 4
Food -> 3
Other category -> 255
Entertainment -> 1
Uncategorized -> 0
Expected result
Uncategorized
Entertainment
Food
Travel
Other category
Actual result
Entertainment
Food
Other category
Travel
Uncategorized
So basically, I wanted the ordering that's shown in the expected results above. Where Uncategorized, having a priority of 0 will be shown first, and the Other category item is shown last, having a priority of 255. Everything in between should be in alphabetical order.

coredata fetch with predicate for object relation using swift

I'm trying to perform a fetch for an entity in coreData. This entity has a one to one relation with another entity. I want to only get the items in the first entity that have a relation to a particular item in the second entity. I'm trying this predicate which I know is incorrect:
let fetchRequest: NSFetchRequest<ItemA> = NSFetchRequest(entityName: "ItemA")
fetchRequest.predicate = NSPredicate(format: "itemA.itemB.itemBId == %d", Int(itemB.itemBId))
Currently you are using itemA.itemB.itemBId , here you are using a new entity of itemA , where as you dont need to give its name, since this predicate will be applied on itemA entity, so either you can use only itemB.itemBId inside predicate or you can use SELF.itemB.itemBId (I am not sure about SELF or self, obviously you can look it up).
So I think you can get the items of type itemA whose relation itemB has an id of itemBId like this:
let fetchRequest: NSFetchRequest<ItemA> = NSFetchRequest(entityName: "ItemA")
fetchRequest.predicate = NSPredicate(format: "itemB.itemBId == %d", Int(itemB.itemBId))

NSFetchedResultsController not calling delegate with predicate #count

I have a fetched results controller which isn't calling its' delegate when it has a predicate. The predicate is to only include Conversation objects which have events:
let predicate = NSPredicate(format: "events.#count > 0")
let fetchRequest = Conversation.MR_requestAllSortedBy(
"mostRecentMessage.eventDate",
ascending: false,
withPredicate: predicate)
self.fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: MagicalRecordStack.defaultStack()!.context,
sectionNameKeyPath: nil,
cacheName: nil)
self.fetchedResultsController.delegate = self
self.fetchedResultsController.MR_performFetch()
This works for an initial fetch, but upon data being added, it doesn't call the delegate. Upon removing the predicate, it does call the delegate.
Is there another way I should be doing this?
The fetch predicate can only check against Core Data attributes because the objects themselves remain as faults. The fetch predicate doesn't get all of the objects of the requested entity and then filter them, it just fetches the ones that pass the filter predicate.
As a work around you could fetch the Event entity. Then use the section key to group by Conversation.

Realm query to exclude results from relations

I have
class Person: Object {
let friends = List<Person>()
let family = List<Person>()
}
I have person instance, which includes links to some other persons in person.friends list.
And I want to query all other Person objects, not including person.friends and person.
I can make two for in loops to check if the query doesn't contain persons from the list, but it seems like not the best way to do that.
P.S. In CoreData I did it with predicate:
let predicate = NSPredicate(format: "SELF != %# AND NOT SELF IN %#",person, person.friends),
But Realm gives me an error:
Predicate expressions must compare a keypath and another keypath or a
constant value
.
Unfortunately, this predicate is currently unsupported in Realm -- you can follow https://github.com/realm/realm-cocoa/issues/1328 for updates.

Predicate for filtering by specific managed object - Swift

I have one to many relationship in my core data model ('Client'<-->>Assessment') and in my assessment tableview I am currently filtering assessments by client name.
func assessmentFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Assessment")
let sortDescriptor = NSSortDescriptor(key: "nsDateOfAssessment", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = NSPredicate(format: "client.name == %#", self.client.name)
return fetchRequest
}
I would like to know how, or if its possible, to filter by the specific managed object instead of an attribute of the managed object ('name' in this case). I've tried changing my predicate to this:
fetchRequest.predicate = NSPredicate(format: "client.objectID == %#", self.client.objectID)
but I just get a crash with an uncaught exception.
I'm wanting to change this because it seems bad practice to filter by name since two clients may have the same name and therefore the same filter results.
So I am going to guess that for you sort descriptor the key name of 'nsDateOfAssessment' is not the actual name of the core data attribute. The key should be the actual name of attribute. Also, I wouldn't say that filtering by first name is bad practice. Perhaps add an additional param to your predicate that can help pinpoint the correct items. Of course, if you are storing a unique identifier for each entity, it would be a cleaner way to go about it.

Resources