Multiple NSPredicates for NSFetchRequest in Swift? - swift

Currently, I have a simple NSFetchRequest with an associated NSPredicate. However, Im hoping there is a way you can append multiple predicates. I've seen examples in Objective C, but none for Swift.
Can you define a list of NSPredicate's or append multiple NSPredicate objects to a single NSFetchRequest somehow?
Thanks!

You can use "NSCompoundPredicate". For example:
let converstationKeyPredicate = NSPredicate(format: "conversationKey = %#", conversationKey)
let messageKeyPredicate = NSPredicate(format: "messageKey = %#", messageKey)
let andPredicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: [converstationKeyPredicate, messageKeyPredicate])
request.predicate = andPredicate
You can change into "AndPredicateType" or "OrPredicateType"

Update for Swift 4
let predicateIsNumber = NSPredicate(format: "isStringOrNumber == %#", NSNumber(value: false))
let predicateIsEnabled = NSPredicate(format: "isEnabled == %#", NSNumber(value: true))
let andPredicate = NSCompoundPredicate(type: .and, subpredicates: [predicateIsNumber, predicateIsEnabled])
//check here for the sender of the message
let fetchRequestSender = NSFetchRequest<NSFetchRequestResult>(entityName: "Keyword")
fetchRequestSender.predicate = andPredicate
The change in latest Swift Version is:
`NSCompoundPredicateType.AndPredicateType` replaced by `NSCompoundPredicate.LogicalType.and`
Hope it helps!!!
Thanks

Related

Core Data - One to Many relationship fetch AND filter via property

My Data Model
A Client can have many Assessments but an Assessment can only have one Client as an inverse relationship. My aim is to fetch all the Assessments that a Client has and also filter based on the "firstName" property of the initial Client.
My Filter Function:
func filterData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let words = textInSearchField.components(separatedBy: " ")
for word in words{
if (word).count == 0{
continue
}
let firstNamePredicate = NSPredicate(format: "firstName contains[c] %#", word)
let lastNamePredicate = NSPredicate(format: "lastName contains[c] %#", word)
let idPredicate = NSPredicate(format: "id contains[c] %#", word)
// I am using a Compound Predicate so that I can filter by first name, last name but also the id property.
let orPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: [firstNamePredicate, lastNamePredicate, idPredicate])
clientsEntity.predicate = orPredicate
// results is an array of type [NSManagedObject], I am using the compound predicate I created above to fetch specific clients.
results = try! context.fetch(clientsEntity) as! [NSManagedObject]
}
}
I essentially want to get all the Assessments of a Client filtering by the firstName, lastName or ID. Is NSPredicate the best approach?
Thank you.

Swift NSPredicate, first name AND last name NSCompoundPredicate?

In my code below I am using NSPredicates specifically I am using NSCompoundPredicate to check for multiple different parameters in my search function. How would I go about searching with both the First Name AND Last Name, I am currently using AND but it does not return anything in my UITableView. All my other predicates listed in the compound predicate work great.
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
textInSearchField = searchBar.text!
if searchBar.text == ""{
print("Searching for all clients.")
retrieveClients()
view.endEditing(true)
clientTableView.reloadData()
}else{
print("Enter a client name to search.")
isFilteringSearch = true
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let firstAndLast = NSPredicate(format: "firstName = %# AND lastName = %#", textInSearchField)
let firstNamePredicate = NSPredicate(format: "firstName = %#", textInSearchField)
let lastNamePredicate = NSPredicate(format: "lastName = %#", textInSearchField)
let idPredicate = NSPredicate(format: "id = %#", textInSearchField)
let orPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: [firstAndLast,firstNamePredicate, lastNamePredicate, idPredicate])
clientsEntity.predicate = orPredicate
clients = try! context.fetch(clientsEntity) as! [NSManagedObject]
view.endEditing(true)
clientTableView.reloadData()
}
}
Something to bear in mind is that I still need to be able to use
LogicalType.or since I want to have the option for the user to search by first name, last name but also a combination of both for example Harold Finch or Finch/Harold etc.
Cheers!
let firstAndLast = NSPredicate(format: "firstName = %# AND lastName = %#", textInSearchField)
let firstNamePredicate = NSPredicate(format: "firstName = %#", textInSearchField)
let lastNamePredicate = NSPredicate(format: "lastName = %#", textInSearchField)
let idPredicate = NSPredicate(format: "id = %#", textInSearchField)
let orPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: [firstAndLast,firstNamePredicate, lastNamePredicate, idPredicate])
I hope that for orPredicate, it should be [firstAndLast, idPredicate] instead, but you didn't make it work. Else you need to rethink about it, that's your orPredicate current logic:
if ((a == x AND b == x) OR (a == x) OR (b == x) OR (c = x)) {
}
The (a == x AND b == x) is useless.
There is an issue on that line:
let firstAndLast = NSPredicate(format: "firstName = %# AND lastName = %#", textInSearchField)
You have two placeholders (%#), but only one argument (textInSearchField).
let firstAndLast = NSPredicate(format: "firstName = %# AND lastName = %#", textInSearchField, textInSearchField)
Thank for the help, I ended up using an alternative method with contains[c] my code is below for anyone who needs help with a similar function, you can use contains[c](contains character) to search via character specifically this applies to all strings i.e first name or last name and in my case also an ID which is stored as a String also.
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
textInSearchField = searchBar.text!
if searchBar.text == ""{
retrieveClients()
view.endEditing(true)
clientTableView.reloadData()
}else{
isFilteringSearch = true
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let words = textInSearchField.components(separatedBy: " ")
for word in words{
if (word).count == 0{
continue
}
let firstNamePredicate = NSPredicate(format: "firstName contains[c] %#", word)
let lastNamePredicate = NSPredicate(format: "lastName contains[c] %#", word)
let idPredicate = NSPredicate(format: "id contains[c] %#", word)
let orPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: [firstNamePredicate, lastNamePredicate, idPredicate])
clientsEntity.predicate = orPredicate
}
clients = try! context.fetch(clientsEntity) as! [NSManagedObject]
view.endEditing(true)
clientTableView.reloadData()
}
}
I followed the second answer on this post NSPredicate: Combine CONTAINS with IN
Thank You

Swift combining predicates LogicalType AND OR

How can i combine a mix AND OR condition in Swift predicate. I have a following query
Select * from tblTemp where dept == 1 && (subdept == 11 || subdept == 12)
I can write two predicate with same operator but don't know how to combine them
let deptPredicate = NSPredicate(format: "dept == %#", 1)
let subdeptPredicate1 = NSPredicate(format: "subdept = %#", 11)
let subdeptPredicate2 = NSPredicate(format: "subdept = %#", 12)
let andPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.and, subpredicates: [deptPredicate, subdeptPredicate1])
NSCompoundPredicate is a subclass of NSPredicate, which means
that the result of
NSCompoundPredicate(type:subpredicates:) can be used in another compound
predicate.
Note however that the %# format placeholder expects an NSObject
instance:
let deptPredicate = NSPredicate(format: "dept == %#", 1 as NSNumber)
let subdeptPredicate1 = NSPredicate(format: "subdept = %#", 11 as NSNumber)
let subdeptPredicate2 = NSPredicate(format: "subdept = %#", 12 as NSNumber)
let orPredicate = NSCompoundPredicate(type: .or,
subpredicates: [subdeptPredicate1, subdeptPredicate2])
let andPredicate = NSCompoundPredicate(type: .and,
subpredicates: [deptPredicate, orPredicate])
Alternatively, use the %ld format for integers:
let deptPredicate = NSPredicate(format: "dept == %ld", 1)
// ... etc.
There are also convenience initializers:
let orPredicate = NSCompoundPredicate(orPredicateWithSubpredicates:
[subdeptPredicate1, subdeptPredicate2])
let andPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:
[deptPredicate, orPredicate])
Compound predicates are very useful to combine a dynamic set of
conditions at runtime. On the other hand, if only the values change
then you can simply use "AND" and "OR" within the predicate
format string:
NSPredicate(format: "dept == %ld AND (subdept = %ld OR subdept = %ld)", 1, 11, 12)
Finally note that you can use the #keyPath directive with the
%K placeholder, so that the compiler fills in the correct property
name (thus reducing the chance of typographical errors):
let deptPredicate = NSPredicate(format: "%K == %ld", #keyPath(MyEntity.dept), 1)

Swift 2 Using Predicate can't get any result on my filter

What am I doing wrong ?
import UIKit
var values:NSMutableArray = []
let url = NSURL(string: "URL") // PHP JSON Result
let data = NSData(contentsOfURL: url!)
values = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSMutableArray
var searchtext = "ROYAL"
let resultPredicate = NSPredicate(format: "SELF contains[cd] %#", searchtext)
let filteredCars = values.filteredArrayUsingPredicate(resultPredicate)
Change your code like this
let resultPredicate = NSPredicate(format: "SELF.Vendor contains[cd] %# OR SELF.vendor contains[cd] %# OR SELF.email contains[cd] %#", searchtext, searchtext, searchtext)
let filteredCars = values.filteredArrayUsingPredicate(resultPredicate)
You need to add Key in which you want to filter the text.
Hope this will help you.

How to retrieve CoreData that satisfies a condition swift 2

I have a DB with fields like below
Latitude Longitude Flag
54.1425 98.2564 0
52.1036 94.1458 3
51.1569 92.1458 3
50.1326 91.1458 3
56.1236 93.1458 0
I need to retrieve records that have flag as 3.
let fetchRequest = NSFetchRequest()
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("TABLE_LOCATION", inManagedObjectContext: managedContext)
// Configure Fetch Request
fetchRequest.entity = entityDescription
do {
let result = try managedContext.executeFetchRequest(fetchRequest)
//print(result)
} catch {
let fetchError = error as NSError
print(fetchError)
}
All i have is the above code that retrieves all records from the table TABLE_LOCATION any code or working example is much appreciated
Thanks!
You need to add a NSPredicate to your fetchRequest.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/
fetchRequest.predicate = NSPredicate(format: "flag == %#", "3")
You can use a NSPredicate and set it to the fetchRequest. Create a NSPredicate and set it to the fetchRequest before you execute the fetch request.
fetchRequest.predicate = NSPredicate(format: "flag = 3")
Change Your function to:
func fetchDistinctDataUsingReq(predicate :NSPredicate) -> NSArray {
let fetchRequest = NSFetchRequest()
fetchRequest.predicate = predicate
//Rest of your code
}
Now call this function from using:
let predicate = NSPredicate(format: "flag == %#", 3)
self.fetchDistinctDataUsingReq(predicate)
This is a much better approach and can be reused across fetching. Additionally you can pass the CoreData Table as parameter along with predicate to generalize it.