I have a func getData() which retrieves core data entity, and I want to sort them by date. How can I apply NSPredicate or Predicate to get the data from CoreData sorted by date?
My core data entity:
Entity: Expenses
Attributes:
amount
category
date
func getData() {
let context = appDelegate.persistentContainer.viewContext
do {
expenses = try context.fetch(Expenses.fetchRequest())
} catch {
print("Cannot fetch Expenses")
}
}
Predicates are for filtering your search results. To sort them you need to use an NSSortDescriptor. Assuming you have an attribute on your Expenses entity called date of type Date:
func getData() {
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Expenses>(entityName: "Expenses")
let sort = NSSortDescriptor(key: #keyPath(Expenses.date), ascending: true)
fetchRequest.sortDescriptors = [sort]
do {
expenses = try context.fetch(fetchRequest)
} catch {
print("Cannot fetch Expenses")
}
}
EDIT: I should have mentioned that the sort selector is added in an array so that multiple sort descriptors can be added if needed. e.g. sort first by date, then by number of legs, then by volume, etc.
You need a sort descriptor to get all the objects in a specific order.
let sectionSortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let sortDescriptors = [sectionSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
My function to do a fetchRequest of data in Core Data and sort the results by date "timestamp" in descending order. "Ruta" is the name of the entity.
//Array of Ruta entity
rutas = [Ruta]()
func getData() {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Ruta")
let sort = NSSortDescriptor(key: "timestamp", ascending: false)
request.sortDescriptors = [sort]
do {
rutas = try context.fetch(request) as! [Ruta]
} catch {
print("Fetching Failed")
}
}
In swift 4 or swift 5, you can use like
func sortlist(){
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "User")
let sort = NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [sort]
//3
do {
let langugeCodes = try managedContext.fetch(fetchRequest)
for result in langugeCodes as [NSManagedObject] {
var username:String = result.value(forKey: "username")! as! String
print("username==>",username)
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
To get data which are lastly added at first, need to set key of sort descriptor as ObjectId.
let sectionSortDescriptor = NSSortDescriptor(key: #keyPath(Entity.ObjectId)
ascending: false) fetchRequest.sortDescriptors = [sectionSortDescriptor]
Related
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)
I'm having trouble creating with CloudKit References. Data is being saved into CloudKit but its not referencing its parent (list). Don't know what i'm doing wrong, any help would be much appreciated!
Saving Method
var list: CKRecord?
var item: CKRecord?
#objc func save() {
let name = nameTextField.text! as NSString
//Fetch Private Database
let privateDatabase = CKContainer.default().privateCloudDatabase
if item == nil {
//Create Record
item = CKRecord(recordType: RecordTypeItems)
//Initialization Reference
guard let recordID = list?.recordID else { return }
let listReference = CKRecord.Reference(recordID: recordID, action: .deleteSelf)
item?.setObject(listReference, forKey: "list")
}
item?.setObject(name, forKey: "name")
//Save Record
privateDatabase.save(item!) { (record, error) in
DispatchQueue.main.sync {
self.processResponse(record: record, error: error)
}
}
}
Fetch Method
var list: CKRecord!
var items = [CKRecord]()
private func fetchItems() {
//Fetch Private Database
let privateDatabase = CKContainer.default().privateCloudDatabase
//Initialize Query
guard let recordID = list?.recordID else { return }
let reference = CKRecord.Reference(recordID: recordID, action: .deleteSelf)
let query = CKQuery(recordType: RecordTypeItems, predicate: NSPredicate(format: "list == %#", [reference]))
//Configure Query
query.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
//Peform Query
privateDatabase.perform(query, inZoneWith: nil) { (records, error) in
DispatchQueue.main.sync {
self.processResponseForQuery(records: records, error: error)
}
}
}
Where you are creating your query to retrieve items referencing the list, should the list reference in the predicate format string be inside an array? If you create the item's reference like item?.setObject(listReference, forKey: "list"), CloudKit will infer the list field to be a single CKRecord.Reference, so the query would be:
let query = CKQuery(recordType: RecordTypeItems, predicate: NSPredicate(format: "list == %#", reference))
This question already has an answer here:
Fetching selected attribute in entities
(1 answer)
Closed 4 years ago.
I cannot fetch data by "name" column. When respone, system print all attribute in People. Help me, thanks.
private func getPeople(product: String) {
let temp = product
let entityDescription = NSEntityDescription.entity(forEntityName: "People", in: context)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
fetchRequest.entity = entityDescription
fetchRequest.includesPropertyValues = true
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.predicate = NSPredicate(format: "product == %#", temp)
fetchRequest.propertiesToFetch = ["name"]
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let personList = try context.fetch(fetchRequest) as! [People]
print(personList)
} catch let error as NSError {
print(error)
}
}
To fetch only specific properties the resultType of the request must be dictionaryResultType
private func getPeople(product: String) {
let fetchRequest = NSFetchRequest<NSDictionary>(entityName: "People")
fetchRequest.predicate = NSPredicate(format: "product == %#", product)
fetchRequest.resultType = .dictionaryResultType
fetchRequest.propertiesToFetch = ["name"]
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let personList = try context.fetch(fetchRequest) as! [[String:String]]
print(personList)
} catch {
print(error)
}
}
}
How can I sort fetchResult by Turkish language, turkish characters sorted at the end of results.
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let fetch = NSFetchRequest<Contact>(entityName: "Contact")
let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: true)
let sortDescriptors = [sortDescriptor]
fetch.sortDescriptors = sortDescriptors
do {
let list = try managedObjectContext.fetch(fetch)
} catch {
fatalError("Failed \(error)")
}
Working code:
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let fetch = NSFetchRequest<Contact>(entityName: "Contact")
let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare))
let sortDescriptors = [sortDescriptor]
fetch.sortDescriptors = sortDescriptors
do {
let list = try managedObjectContext.fetch(fetch)
} catch {
fatalError("Failed \(error)")
}
Recipe
recipeID: Int
recipeName: String
I have an entity Recipe with an attribute recipeID.
How can I get the max(recipeID) as an Int value in Swift?
I'm new in swift, please help me.
Thanks in advance.
func fetchMaxID() {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Recipe")
fetchRequest.fetchLimit = 1
let sortDescriptor = NSSortDescriptor(key: "recipeID", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
let maxID = try [managedObjectContext?.executeFetchRequest(fetchRequest)].first
print(maxID)
} catch _ {
}
}
The way that Apple recommends and is the fastest is using NSExpressions. moc is a NSManagedObjectContext.
private func getLastContactSyncTimestamp() -> Int64? {
let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest()
request.entity = NSEntityDescription.entity(forEntityName: "Contact", in: self.moc)
request.resultType = NSFetchRequestResultType.dictionaryResultType
let keypathExpression = NSExpression(forKeyPath: "timestamp")
let maxExpression = NSExpression(forFunction: "max:", arguments: [keypathExpression])
let key = "maxTimestamp"
let expressionDescription = NSExpressionDescription()
expressionDescription.name = key
expressionDescription.expression = maxExpression
expressionDescription.expressionResultType = .integer64AttributeType
request.propertiesToFetch = [expressionDescription]
var maxTimestamp: Int64? = nil
do {
if let result = try self.moc.fetch(request) as? [[String: Int64]], let dict = result.first {
maxTimestamp = dict[key]
}
} catch {
assertionFailure("Failed to fetch max timestamp with error = \(error)")
return nil
}
return maxTimestamp
}
Learning from Ray Wenderlich's Core Data Tutorial
https://www.raywenderlich.com/115695/getting-started-with-core-data-tutorial/
func fetchMaxRecipe() {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Recipe")
fetchRequest.fetchLimit = 1
let sortDescriptor = NSSortDescriptor(key: "recipeID", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
let recipes = try context.executeFetchRequest(fetchRequest) as! [Recipe]
let max = recipes.first
print(max?.valueForKey("recipeID") as! Int)
} catch _ {
}
}
Hope this helps =).
func fetchMaxID() {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Recipe")
fetchRequest.fetchLimit = 1
let sortDescriptor = NSSortDescriptor(key: "recipeID", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
let results = try context.executeFetchRequest(fetchRequest) as! [Recipe]
if (results.count > 0) {
for result in results {
print(result.recipeID!)
}
} else {
print("No Recipe")
}
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
}
This works also!
To check the max of an entity attribute you can simply use:
func findMaxRecipeID() -> Int {
let maxRecipeID = recipe?.value(forKeyPath: "recipe.#max.recipeID") as! Int
return maxRecipeID
}
You can use this to #sum, #max, #min, #count - saves quite a few lines of code.