Distinct value from core data swift - swift

i want to get distinct dates from core data.
with this code fetchRequest.returnsDistinctResults = true is not working.
it is still showing all values.
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Journal")
fetchRequest.propertiesToFetch = ["dateAsNumber"]
fetchRequest.returnsDistinctResults = true
do {
dateListSquare = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}

If you want distinct results, you need to set the fetch request's result type to NSFetchRequestResultType.dictionaryResultType. You can't fetch managed objects and get distinct results, since there might be more than one managed object with the same value.
That would look something like
let fetchRequest: NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: "Journal")
fetchRequest.propertiesToFetch = ["dateAsNumber"]
fetchRequest.returnsDistinctResults = true
fetchRequest.resultType = .dictionaryResultType
The result will be an array of dictionaries. Each will have one key per entry in propertiesToFetch (just one in this case).
If you use propertiesToFetch without dictionaryResultType, you affect how faulting works but not the contents of the result. Using returnsDistinctResults only works if you also use propertiesToFetch, so it's also affected by whether you use dictionaryResultType.

Related

What's the syntax for updating existing attributes in core data compared to saving a new object in core data?

How is the syntax for adding new data to core data different from updating existing data in core data. For instance, if I have a core data entity of Person and attributes name: String, gender: String, and last_occupation: [Int : String](where Int corresponds to their age when they quit), I am confused which of the two syntax I already know I should use.
let appDelegate = UIApplication.shared.delegate as? AppDelegate
let context = appDelegate.persistentContainer.viewContext
let container = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person
//And then assigning attributes
container.name = some_string
container.gender = some_string
container.last_occupation = custom_object_that_conformsTo_codable_protocol
VS
let fetchRequest = NSFetchRequest(entityName: "Person")
let results = try context.fetch(fetchRequest)
if let container = results.first {
container.name.value = some_string
container.gender.value = some_string
container.last_occupation = custom_object
try context.save()
context.refresh(transformableContainer, mergeChanges: false)
}
When should I use one method over another, and if I know that I will be replacing existing attributes in core data with newly updated ones instead of just changing their values, is it okay to use the first method?
The first syntax inserts a new record – you have to save the context afterwards.
The second syntax fetches existing data and updates a record.
However to update a specific record you have to add a predicate and most likely you don't want to update the name and the gender attributes
let name = "John Doe"
let fetchRequest : NSFetchRequest<Person> = Person.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %#", name)
let results = try context.fetch(fetchRequest)
if let container = results.first {
// container.name = some_string
// container.gender = some_string
container.last_occupation = custom_object
try context.save()
context.refresh(transformableContainer, mergeChanges: false)
}

NSSortDescriptor has no effect on Core Data fetch request

My Core Data entity "Entry" has 4 attributes, including the attribute "key", which I want to sort by. "key" is non-optional and unique. Core Data structure:
I am fetching objects from Core Data like this:
var entries: [NSManagedObjectID : NSManagedObject] = [:]
class func fetchEntriesfromPersistentStore () {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Entry")
let sort = NSSortDescriptor(keyPath: \Entry.key, ascending: true)
fetchRequest.sortDescriptors = [sort]
do {
let fetchesEntries = try managedContext.fetch(fetchRequest)
entries = Dictionary(uniqueKeysWithValues: fetchesEntries.map{ ($0.objectID, $0) })
} catch let error as NSError {
print("Could not fetch entries. \(error), \(error.userInfo)")
}
}
I also tried the following initialisation of the NSSortDescriptor like in the official documentation:
let sort = NSSortDescriptor(key: "key", ascending: true)
The resulting dictionary is always in random order, i.e. in different order on every execution. I confirmed that code above is executed. Removing the NSSortDescriptor also has no effect on the results.
I inspected the list fetchesEntries before the objects are stored in the dictionary, and it is not sorted.
iOS Deployment Target is 13.4, Swift 5.0, Xcode 11.5, macOS 10.15.5
try
let sort = NSSortDescriptor(key: #keyPath(Entry.key), ascending: true)

swift core data executeFetchRequest always crash with propertiesToGroupBy

i am having a problem with executeFetchRequest when i use propertiesToGroupBy. I need to fetch dates(saved as string) but similar dates should be avoided, so that i get unique date array. below is the code i used
var arrDates: NSArray = NSArray()
let fetchRequestDates = NSFetchRequest(entityName: "Schedule")
fetchRequestDates.propertiesToGroupBy = ["date"]
fetchRequestDates.propertiesToFetch = ["date"]
fetchRequestDates.resultType = .DictionaryResultType
do {
let result = try managedContext.executeFetchRequest(fetchRequestDates)
arrDates = result as NSArray
} catch {
NSLog("Failed to fetch dates: \(error)")
}
the execution doesn't go further
let result = try managedContext.executeFetchRequest(fetchRequestDates)
and causing SIGBART. If I comment
fetchRequestDates.propertiesToGroupBy = ["date"]
it works but will fetch duplicate dates too. what is the work around?

saving, deleting and fetching data from a one to many relationship core data

I have created a data model like so:
I have this code for a fetch request:
func roundFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Customer")
print("Check here: \(myRoundIndexPath)")
//let predicate : NSPredicate = NSPredicate(format: "custRoundRel = %#", frc2.objectAtIndexPath(myRoundIndexPath!) as! RoundName) //ASSUME THIS IS CORRECT
let sortDescriptor = NSSortDescriptor(key: "c2fna", ascending: true)
//fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
My commented out code does not give an error, but I cannot seem to save a customer to the RoundName instance. When I save a customer with its attributes, I have used this code:
func newCust() {
let cont = self.context
let newCustomer = NSEntityDescription.entityForName("Customer", inManagedObjectContext: cont)
let aCust = Customer(entity: newCustomer!, insertIntoManagedObjectContext: cont)
aCust.c2fna = firstName.text
aCust.c3lna = lastName.text
aCust.c4tel = tel.text
aCust.c5mob = mob.text
aCust.c6ema = email.text
aCust.c7hsn = houseNo.text
aCust.c8fir = street.text
aCust.c9sec = secondLine.text
aCust.c10ar = area.text
aCust.c11pc = postcode.text
aCust.c12cos = cost.text
aCust.c13fq = frequencyNumber.text
aCust.c14fqt = frequencyType.text
let DF = NSDateFormatter()
aCust.c15das = DF.dateFromString(startDate.text!)
//Do Pics in a minute & next date in a minute
aCust.c17notes = notes.text
//print("Desc = \(picRound.image?.description)")
do {
try context.save()
print("Save Successful")
} catch {
print("Save Unsuccessful")
}
}
What is the code to link this customer with the correct Round?
Thanks, I am very new to core data and really would appreciate any help.
Yes, you use a predicate on your fetch request, with a format like
NSPredicate(format:"custRoundRel = %#", xxxx)
where xxxx is the Round instance.
You can also just use the roundCustRel relationship depending on what you want to do with the Customer instances and how many there are.
You create Customer objects in the same way you create other managed objects. To link a customer with the correct Round object, just set the to-one relationship (Core Data will automatically set the reverse relationship for you).
newCustomer.round = round
// or, with your arcane attribute names
newCustomer.custRoundRel = theDesiredRoundObject
To get to the customers of one specific round, you do not need fetch requests or predicates.
round.customers
// or, with your arcane attribute names
round.roundCustRel

Swift: How to filter in Core Data

I'm using the following code to fetch all the data in "category".
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest(entityName:"category")
let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject]?
How do I only brings categories where the "type" is equal to "products"?
To "filter" results in Core Data, use NSPredicate like so:
let filter = "products"
let predicate = NSPredicate(format: "type = %#", filter)
fetchRequest.predicate = predicate
So, in the below example
In the first step, we will add give the value we want to filter.
In the second step, we will add a predicate in which we will give the DB key we want to get the value in my case is "id" and besides this a value, we want to filter.
In the Third step assign the entity name where your all data has saved in the NSFetchRequest.
After that assign the predicate.
Use context object to fetch the object.
private let context = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let filter = id
let predicate = NSPredicate(format: "id = %#", filter)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"TodoListItem")
fetchRequest.predicate = predicate
do{
let fetchedResults = try context.fetch(fetchRequest) as! [NSManagedObject]
print("Fetch results")
if let task = fetchedResults.first as? TodoListItem{
print(task)
}
// try context.save()
}catch let err{
print("Error in updating",err)
}
You can use .filter on the fetchedResults.