I have
class Car : Object
{
let queries : List<QueryModel> = List<QueryModel>()
}
and
class QueryModel : Object
{
let location : String = ""
}
Now how do I write that NSPredicate to fetch just that cars which have queries with location equal to 'London'?
p.s. It's a known fact that things like #count do not work on Swift List class...
p.p.s. I need it as a predicate because this is the only way RBQFetchedResultsController knows how to do it's job.
How I thought it could've been written was something like NSPredicate(format: "SUBQUERY(queries, $query, $query.location == %#)", 'London'). But nothing like this ever passes Realm's predicate validation :)
You can write
NSPredicate(format: "ANY queries.location = %#", locationString)
If you want to add other filtering, you can create other NSPredicate and then use
NSCompoundPredicate(andPredicateWithSubpredicates: [pred1, pred2])
to combine the filters.
Now, if you want to filter cars, you have to prepare a
let request = FetchRequest<Car>(realm: realm, predicate: predicate)
then you can use RBQFetchedResultsController to execute the request.
Related
I'm a bit lost, and I hope you can help me.
I have two arrays
let stars = ["Paul", "Ringo"]
let visitors = ["bob", "mary"]
Then I have Core Data entities Rockstar and Person. And a one-to-many relation fans between the two.
Now I want to find a couple of specific Rockstars, and make sure that they don't have visitors as fans.
I try to do that with a compound predicate, roughly like this:
let starsPredicate = NSPredicate(format: "id IN %#", stars)
let fansPredicate = NSPredicate(format: "NOT (fans.personid CONTAINS %#)", visitors)
and finally
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [starsPredicate, fansPredicate])
I'm afraid this results in two questions:
What is the correct syntax for the fansPredicate? It works fine with one value, but it crashes on an array
Is this possible with a compound predicate at all? I think if the Person entity is empty, I get zero records from the compoundPredicate.
This can be achieved with a “SUBQUERY”:
let fansPredicate = NSPredicate(format: "SUBQUERY(fans, $f, $f.personid IN %#).#count = 0",
visitors)
The predicate is true for all Rockstar objects which have no related Person object whose personId is in the given list.
I am unable to fetch data using a string as a direct argument to NSPredicate. Is there any difference between these two,
//Working case
fetchRequest.predicate = NSPredicate(format: "role == %#","GK")
In the above case, I am able to fetch the data with the predicate.
//Not Working
predicateString = String(format:"role == %#","GK")
fetchRequest.predicate = NSPredicate(format: predicateString)
Here I am unable to fetch the data.
The only difference between the above two cases is that I'm using a String variable to define the predicate. What is wrong here?
When the %# is replaced with a string variable when instantiating a NSPredicate the string variable is automatically surrounded by quotes so in your example the predicate becomes role == 'GK'
If you want to use String(format:...) you need to add the quotes yourself but in my opinion it's better to use NSPredicate(format:...) directly instead to avoid issues like this.
Format of NSPredicate is as following, where it expects a format, and format contains equaliser.
NSPredicate(format: <String>, <args: CVarArg...>)
let predicate1 = NSPredicate(format: "role == %#", "GK")
Here, if you will check the predicate1.predicateFormat, then you will get:
"role == \"GK\"",
which equilise role with string "GK" and return result in array.
But for,
let predicateString = String(format:"role == %#","GK")
let predicate2 = NSPredicate(format: predicateString)
You replaced the equaliser with simple string, which fails to return anything. You can check with predicate1.predicateFormat which will return:
"role == GK"
Here you can use "role == 'GK'" if you want to use string.
Hope it will help.
I got stuck with a problem regarding the NSPredicate syntax. I want to filter an array of objects by their class types.
class ClassA: NSObject {}
class ClassB: ClassA {}
class ClassC: ClassA {}
let array: [ClassA] = [ClassB(), ClassC()]
Now I want to use an NSPredicate to get a filtered array only with ClassB items.
I could use Blocks to do so, and it would be something like this:
let predicate = NSPredicate { (object, nil) -> Bool in
return object is ClassB
}
Although this is a legitimate approach, I also want to do the exact same thing with NSPredicate(format:).
Among other attempts I unsuccessfully tried the following:
let predicate = NSPredicate(format: "self = %#", [ClassB.self])
let predicate = NSPredicate(format: "SELF isKindOfClass: %#", [ClassB.self])
I think it must be just a syntax problem, but I'm looking for over an hour to solve this with no result.
Thanks in advance.
This should work:
let predicate = NSPredicate(format: "class = %#", ClassB.self)
Here is a documentation page about predicates - https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/Articles/pCreating.html#//apple_ref/doc/uid/TP40001793-CJBDBHCB
I did manage to do this by making a function with a loop that checks the attribute to a string. But i'm looking for a better way to do this.
In sql I do this:
Select * WHERE "attribute" == "string"
Is there a method to do this in swift?
My function looks like this:
func tableData()
{
let objects = retrieveValues("JobTime") //Retrieve a NSMutableArray
if !objects.isEmpty
{
for var index = 0; index < objects.count; ++index
{
if objects[index].valueForKey("jobTitle") as? String == transferTitle
{
print("Job title matched: \(index)")
}
else
{
print("Nothing here!")
}
}
}
}
In order to perform fetch request in CoreData you have to initialise NSFetchRequest class. In order to specify in what kind of entities you are interested you create NSPredicate class. It gives you ability to specify pretty advanced queries. In most cases the simplest way to create NSPredicate is by using format string - details about the syntax can be found Apple's Predicate Format String Syntax document.
You can find example of how you can perform fetch request in CoreData (and Swift) below.
let managedObjectContext: NSManagedObjectContext
let predicate = NSPredicate(format: "jobTitle == %#", "Programmer")
let fetchRequest = NSFetchRequest.init(entityName: "People")
fetchRequest.predicate = predicate
//fetchRequest.sortDescriptors = [] //optionally you can specify the order in which entities should ordered after fetch finishes
let results = managedObjectContext.executeFetchRequest(fetchRequest)
You can pass the query to CoreData and only retrieve what you want. The NSManagedObjectContext class has a executeFetchRequest method that you call to retrieve data from the database. You pass NSFetchRequest object to it. That object contains a NSPredicate, which defines your query.
I have
class Person: Object {
let friends = List<Person>()
let family = List<Person>()
}
I have person instance, which includes links to some other persons in person.friends list.
And I want to query all other Person objects, not including person.friends and person.
I can make two for in loops to check if the query doesn't contain persons from the list, but it seems like not the best way to do that.
P.S. In CoreData I did it with predicate:
let predicate = NSPredicate(format: "SELF != %# AND NOT SELF IN %#",person, person.friends),
But Realm gives me an error:
Predicate expressions must compare a keypath and another keypath or a
constant value
.
Unfortunately, this predicate is currently unsupported in Realm -- you can follow https://github.com/realm/realm-cocoa/issues/1328 for updates.