coredata fetch records where the relation is not existing - swift

I have an entity in swift with an optional relation towards another entity. Now I want to select those records without a relation towards the other entity.
I tried with a predicate (format: "relation = %#", nill) but this does not work.
how to fetch records without the relation filled?

Try this:
let fetchRequest: NSFetchRequest = YourEntity.fetchRequest()
let predicate = NSPredicate(format: "%K == nil", #keyPath(YourEntity.yourOptionalAttribute))
fetchRequest.predicate = predicate
// the rest of your code to perform the fetch goes here
#K is for keyPath. You just want to search where the keyPath is nil.

Related

Swift CoreData: accessing relationship is slower than just fetching by predicate - is it designed that way?

In my app I have 100 libraries that contain 5000 books each.
If I want to print 10 libraries and their 10 most recent additions, I can either fetch them all by accessing the relationship, then .suffix the returned NSSet and run a sort OR I can find the libraries by leaving a libraryID property that I can later use in an NSPredicate such as the following:
let fetchRequest = ... "Library"
let sort = NSSortDescriptor(key: "some key for ordering", ascending: false)
fetchRequest.sortDescriptors = [sort]
fetchRequest.fetchLimit = 10
let libraries = try context.fetch(fetchRequest) as? [Library]
for library in libraries {
let fetchRequest = "Book"
fetchRequest.fetchLimit = 10
let predicate = NSPredicate(format: "libraryID == %#", library.id ?? "")
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "added date", ascending: false)]
...
}
What I do not understand is why the second option uses 15% of the CPU, whereas accessing the relationship directly is about 10 times slower.
My understanding of databases was that we have relationships in place to prevent doing exactly these kinds of things, somewhat hardcoding the ID of a parent property into a child property because now I am questioning what relationships are even good for.
There is one thing where I could see a relationship coming along useful, namely if we were able to perform a .fetch right on the Library object or it's books relationship - is that possible? Because then we wouldn't have to scan the whole table each time but instead only search within the entries of the relationship.
Accessing via the relationship, then sorting and discarding 4950 / 5000 items means that all of that processing has to be done in memory. Using fetch requests means that you can get the database to do the work.
If you have a relationship between the library and its books, you can use that in a predicate. In your code above, that would be something like:
let predicate = NSPredicate(format: "library == %#", library)
That will likely be faster than storing the ID, unless you have an index added on library ID.

Filter to NSFetchRequest

hi i'm not really understanding how the fetch filter works can anyone help me please? So i currently have this as my fetchall function which displays all of my items within my entity
im having trouble of filtering only one attribute which is a boolean. I want it to only display attributes that are true.
thankyou!
func fetchAllItems(){
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "AllItems")
do{
let result = try managedObjectContext.fetch(request)
beastList = result as! [AllItems]
} catch { print("\(error)")
}
}
Code:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "AllItems")
request.predicate = NSPredicate(format: "something = %#", argumentArray: [true])
Note: Replace something with your boolean field name
Better way to create request
let request : NSFetchRequest<AllItems> = AllItems.fetchRequest()
Naming convention:
It is better to name your entity in singular form, so that each row in your entity could be in singular form.
AllItems seems very generic, if you are storing cars, the entity name could be Car. The variable that stores the result of the fetch request could be cars.
Reference:
https://developer.apple.com/documentation/foundation/nspredicate
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html

CloudKit Server Rejected Request: Unknown field recordName

I am doing a CKQuery like this in Swift 4:
CKQuery(recordType: package.recordType, predicate:
NSPredicate(format: "NOT (recordName IN %#)", package.recordNames as CVarArg))
...and I'm getting this CKError:
CKError(_nsError: CKError 0x60000024dce0: "Server Rejected Request" (15/2000); server message = "Unknown field 'recordName'"; uuid = BCD7C8DA-04B0-4422-8A24-F6479D234706; container ID = "...")
Is there a special key to use when querying against the recordName?
After digging some more, I discovered that you cannot query by the recordName directly, but you can query by the recordID. So instead of comparing an array of strings, you have to build an array of CKRecordIDs and query like this:
//- 1 - Build an array of CKRecordIDs
package.recordIDs = [CKRecordID(recordName: "..."), CKRecordID(recordName: "...")]
//- 2 - Set the predicate to use the `recordID` key
let pred = NSPredicate(format: "NOT (recordID IN %#)", package.recordIDs as CVarArg)
//- 3 - Set the query and drop your mic
CKQuery(recordType: package.recordType, predicate: pred)
I hope that helps someone else.

How fetch relationship from CoreData in swift?

I think this is simple but i can't find answer for me. I have two tables. Contacts and messages. Like this:
And my relationships are in contacts
And in Messages
enter image description here
I need take SQL: SELECT contacts.nickName, messages.id, messages.message FROM messages JOIN contacts.ccNumber = messages.senderCcNumber
My code for now getting a all data from Messages but i don't know how to join table Contacts to this fetch.
let appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context: NSManagedObjectContext = appDel.managedObjectContext
let request: NSFetchRequest = NSFetchRequest(entityName: "Messages")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "senderCcNumber = %#", argumentArray: ["\(senderID)"] )
request.sortDescriptors = [NSSortDescriptor(key: "added", ascending: true)]
do { resultsMessagesList = try context.executeFetchRequest(request) } catch {}
print(resultsMessagesList)
return resultsMessagesList
Can someone give me a hint ?
CoreData is not a database. You don't need to join any tables (there are no tables).
You shouldn't be storing any foreign keys either.
Once you have a message you can get the contacts array by using message.contacts. You don't need to execute any fetch requests to do this. (Other than to get the message in the first place).
Also, your entities should have singular names (Contact not Contacts).
If your messages have a sender and a receiver then create two relationships one called sender and the other called receiver and connect them to the Contact entity.
I'd recommend investing in a CoreData basics book. Or there are some very good tutorials online. You would be saving yourself time in learning to use CoreData properly.

How to sort the results of an NSFetchedResultsController using the order of an NSOrderedSet

NSOrderedSets save the order of the objects in the table. If you access an NSManagedObject subclass instance with a property that is an NSOrderedSet, then they will be in order.
However, there is seemingly no way to access that order using an NSSortDescriptor when creating an NSFetchRequest.
It appears from the raw SQLite DB, that order is stored in fields named Z_FOK_<relationship name>. The data is available, but it doesn't appear to be visible through the core data APIs.
Does anyone know a way to write an NSSortDescriptor that will work with a SQLite DB to return the results in the order specified by the NSOrderedSet?
Update
Related Question: NSFetchedResultsController and NSOrderedSet relationships
I don't think that is possible. The "ordering" is associated with the to-many relationship from one entity A to another entity B, it is not a property of the target entity B.
But a sort descriptor for a Core Data fetch request can only use (persistent) properties of the entity.
I've tried this in swift just now and it seemed to work for me.
var sectionsExcludingEmpty: [SurveyAnswerSection] {
let fetchRequest: NSFetchRequest<SurveyAnswerSection> = NSFetchRequest.init(entityName: "SurveyAnswerSection")
fetchRequest.predicate = NSPredicate.init(format: "surveyAnswer == %# AND hidden == FALSE", self)
fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "surveyAnswer", ascending: true) ]
if let moc = self.managedObjectContext {
do {
let results = try moc.fetch(fetchRequest)
return results
} catch {
fatalError("Could not get sectionsExcludingEmpty: \(error)")
}
} else {
fatalError("Unable to get own managed object context")
}
}
When I missed off the line fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "surveyAnswer", ascending: true) ] it ordered seemingly randomly, but with the line added it sorted as expected.
In my case SurveyAnswerSection has a one to ordered-many relationship with SurveyAnswer.