I have a requirement for the enterprise app that I'm working on where the SQL queries are stored in the system.
For example:
WORKTYPE not in('PM','PM1','EV','OP')
:worktype <>'PM' AND :worktype <>'PM1' AND
:worktype <>'EV' AND :worktype <>'OP'
WORKTYPE n :worktype are the attributes of an entity
PM, PM1, EV and OP are the values to be filtered
=======================================================================
These are some of example where clauses that I have to handle in the NSPredicate.
Programming Language: Swift 4
Database: Coredata
Any suggestion of how to handle these expressions ?
You can create NSPredicate at run time and at the end combine predicate using NSCompoundPredicate. Like in below syntax
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1, predicate2])
BTW - I agree with the comments - you should provide more information in your question and explain what you have tried, including attempts at code, etc... however failing that...
Read about the NSExpression class, from the Apple Developer documentation...
NSExpression
An expression for use in a comparison predicate.
Overview
Comparison operations in an NSPredicate are based on two expressions, as represented by instances of the NSExpression class.
Expressions are created for constant values, key paths, and so on.
Although it is an archived document, Apple's "Predicate Programming Guide" is still relevant to those using predicates with Core Data in both Swift and Objective-C. I recommend you read it.
Within this documentation, I specifically point you to...
Creating Predicates > Creating Predicates Using Predicate Templates
The example from the documentation (translated to Swift)...
The following example uses a format string to create a predicate with
a right-hand side that is a variable expression.
let predicateTemplate = NSPredicate(format: "lastName like[c] %#", argumentArray: [$LAST_NAME])
This is equivalent to creating the variable expression directly as
shown in the following example.
let lhs = NSExpression(forKeyPath: "lastName"]
let rhs = NSExpression(forVariable: "LAST_NAME"]
let comparisonPredicate = NSComparisonPredicate(leftExpression: lhs,
rightExpression: rhs,
modifier: .direct,
type: .like,
options: [.caseInsensitive])
So enough of the lecture and to your question...
WORKTYPE not in('PM','PM1','EV','OP')
I assume here that you have the knowledge to parse your SQL expressions to extract the information set out in the first two lines of code below.
let keyPath: String = "WORKTYPE"
let arrayWorkTypes: [String] = ["PM", "PM1", "EV", "OP"]
var arrayComparisonPredicates = [NSPredicate]()
for workType in arrayWorkTypes {
let expressionLHS = NSExpression(forKeyPath: keyPath)
let expressionRHS = NSExpression(forConstantValue: workType)
let comparisonPredicate = NSComparisonPredicate(leftExpression: expressionLHS,
rightExpression: expressionRHS,
modifier: .direct,
type: .notEqualTo,
options: [.caseInsensitive])
arrayComparisonPredicates.append(comparisonPredicate)
}
let andPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: arrayComparisonPredicates)
With your andPredicate built dynamically in this manner, you should be able to run your fetch request successfully.
I haven't tested this code so let me know how you go and I'll update if/when necessary.
And finally... your database is not Core Data.
If you’re using the Core Data framework in an Xcode project, your database is most likely SQLite.
Simply and according to Wikipedia, Core Data is “a model object graph and persistence framework...”
I highly recommend that you read and read and read some more until you truly understand the difference. I guarantee it will be a worthwhile investment of your time.
Related
I was using a function to validate email format and password up till now
func isRegexValid(string:String,regex:String) -> Bool {
return NSPredicate(format: "SELF MATCHES %#", regex).evaluate(with: string)
}
I was trying to check a certain pattern and ran into problems. I was looking to find a string with 4 comma delimiters followed by "ext"
^(.*,){4}ext
The above function would not handle this as expected, so I tried an alternative which works well
func isRegexValid2(string:String,pattern:String) -> Bool {
let regex = try! NSRegularExpression(pattern: pattern, options: [])
return regex.firstMatch(in: string, options: [], range: NSMakeRange(0, string.utf16.count)) != nil
}
I would like to understand the differences between the two regex calls and whether we should avoid one or the other.
NSPredicate is very different from NSRegularExpression.
NSPredicate is used for searching and filtering among the Cocoa object. Its primary purpose is to filter certain object among a collection of objects. It has a completely different syntax.
As mentioned in the Apple docs for NSPredicate
Predicates represent logical conditions, which you can use to filter collections of objects.
For further study you can see Predicate programming guide.
On the other hand NSRegularExpression is a class that is used to compile regular expressions that are then applied to unicode strings.
NSRegularExpression class supports standard ICU regular expression defined at http://userguide.icu-project.org/strings/regexp
Hope this clarifies.
I have such function in my data source:
func getAllFood(by type: String) -> [UserFoodInformation] {
var findedFood = [UserFoodInformation]()
findedFood.append(contentsOf: baseUserFoodDataSource.getAllFood(by: type))
let predicate = NSPredicate(format: "foodType == %#", type)
let resultOfSearching = dataBase.objects(AddedUserFood.self).filter(predicate).sorted(byKeyPath: "name")
for searchedFood in resultOfSearching {
findedFood.append(searchedFood)
}
return findedFood
}
When I try to query with string that consist whitespace, I have no result, but if I query with simple one-word parameter, everything goes fine. Why is that? Can I have a string field in Realm that consists multiple words?
The predicate you're using is looking for objects whose foodType property is equal to the type string that is passed in. Only those objects whose property is exactly equal to that string will match. If you want to perform some other form of matching you'll need to use something other than the equality operator. BEGINSWITH, CONTAINS, ENDSWITH and LIKE are the comparison operators that Realm supports on string fields.
Can I have a string field in Realm that consists multiple words?
String fields can contain any string values. The supported comparison operators don't have the concept of a "word", though, so if you want to do filtering using that concept you'll likely need to do further work on your part. Depending on your use case, I can see a couple of ways to go about it:
Use CONTAINS to find any objects whose foodType properties contains the given type string.
Parse the string into structured data that you store in your model. For instance, it may make sense to store a List<FoodType> rather than a String for the foodType property.
There are likely other options, but they depend on details of what it is you're trying to achieve that you've not shared.
I have two class, one is named Folder, the other is named Entry.
In my data model, a folder would contain multiple entry, and an entry can be contained by different folders.
So each folder has a folderID to identify itself, and a relationship named entries which is used to contains Entry instances. And each entry has an inverse relationship named superFolders which points back to the folder contains it.
Now is my question. Here I get a folderID. I want to use this and NSFetchRequest to fetch all the entries contained by this special folder in Core Data. The following is the main code:
let fetchRequest = NSFetchRequest<Entry>(entityName: "Entry")
fetchRequest.predicate = NSPredicate(format: "(ANY folder in %K).folderID = %i", #keyPath(Entry.superFolders), folerID)
The format string in above code is incorrect, but it mostly explain what I mean. Since superFolders property is actually a NSSet in Core Data, I can't use superFolders.folderID == %i as the judge condition. What exactly I want is to find all the entry whose superFolder property contains any of element which its folderID property match the given folderID.
So is that possible to use NSPredicate to express what I mean to Core Data ?
You want:
let fetchRequest = NSFetchRequest<Entry>(entityName: "Entry")
fetchRequest.predicate = NSPredicate(format: "ANY superFolders.folderID = %#", folderID)
See the NSPredicate reference
If you had a more complicated match on the superFolders relationship, you would need to use SUBQUERY, but in this case a simple ANY predicate works fine.
I've got a local db (Realm) with drinks. Each drink has a name.
I want to get all the drinks starting with a certain letter.
This is what I came up with:
let objects = realm.objects(Drank.self)
.filter{($0.name.characters.first)?.description == section}
The problem I am having now is that the objecttype I get is a 'LazyFilterBidirectionalCollection'. But I need Results.
Does anybody know a way to convert it to the correct type or maybe a different way to filter the resultset?
This is straight from the realm docs on sorting/filtering:
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan' AND name BEGINSWITH 'B'").sorted(byProperty: "name")
So to filter something you are looking for maybe something like this:
let objects = realm.objects(Drank.self)
.filter("name BEGINSWITH '\(column)'")
A safer option proposed below by Thomas Goyne,
let objects = realm.objects(Drank.self)
.filter("name BEGINSWITH %#", column)
Since you are now filtering data with the way the docs use you should receive a Results object
Don't be afraid to read documentation, not only will you be able to get the satisfaction of figuring it out on your own, you will also learn a bunch of other things along the way.
I am looking for some assistance in understanding NSPredicates and how to query CoreData. Here is what I have:
I have two entities: 1. Capture that represents a "capture" of some data and it has a to many relationship to 2. Identity tags.
I am looking to essentially get a Set of "Identity" tags from a particular Set of "Captures". i.e. I want to know all the unique identities of name 'X' for captures that are also tagged with an id of Int 'y'.
In swift I would model this like:
let captures: [Capture]
let identities = captures.flatmap({ $0.identities }).filter({ $0.id == "y" })
let uniqueIdentitiesOfParticularType: Set<Identity> = Set(identities.flatMap({ $0.name })
Any help please?
First, definitely start with the Predicate Programming Guide, which covers more of this in detail. See particularly "Using Predicates with Core Data."
Your solution is likely something along these lines if you wanted to be a bit careful about faulting:
let request = NSFetchRequest(entityName: "Capture")
let id = "y"
request.predicate = NSPredicate(format: "id == %#", id)
let identities = try context.executeFetchRequest(request) as NSArray
let names = identities.valueForKeyPath("#distinctUnionOfObjects.name")
Note that iOS 10 adds better bridges for this to Swift (you may not need as NSArray), but I haven't really explored them yet.
For more on #distinctUnionOfObjects and its friends, see Collection Operators.