Suppose we have some PersonClass objects stored in Realm with the following names
Jay
Cindy
Larry
Carl
Linda
and we want to retrieve only Jay, Cindy, Larry and Carl (names ending in ‘y’ or ‘l’). Here ya go using predicates and a compound predicate
//the names we want ending with 'y' or l'
let endStringArray = ["y", "l"]
//array to store the predicates for each letter
var predicateArray = [NSPredicate]()
//iterate through the endStringArray getting each ending letter and creating a predicate
// to retrieve matches for each letter
for endString in endStringArray {
let p = NSPredicate(format: "name ENDSWITH %@", endString)
predicateArray.append(p) //store each predicate in an array
}
//create a compound predicate of all of the above predicates
let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicateArray)
//do the query
let results = realm.objects(PersonClass.self).filter(compoundPredicate)
//output the result
for person in results {
print(person.name)
}
and the output
Jay
Cindy
Carl
Larry
Best to avoid high-level Swift function calls (map, reduce etc) when possible to avoid overloading the memory will large datasets. The above code avoids those entirely and is lazy-loading safe(r)
I am sure I can come up of a more type-safe version using modern API calls if needed.
In my example, would map & reduce have this effect? From what I can tell, they’re just used to build up a query, not to actually transform the result objects themselves.
Yes, we’re very interested in a type-safe version.
Yes. One of the best things about using Realm to back your apps is that Realm Results are lazily-loaded. Meaning that HUGE datasets can be comfortably navigated without having to worry about overloading the devices memory.
In a nutshell, if your app stores information about wine, when the user selects to retrieve every Cabernet Sauvignon (which is a LOT), Realm will just breeze through it and run that query and the results will easily contain those Cabernets.
However. if you use Swift High Order functions, like map, reduce, filter, compactMap etc. to work with those results, that laziness goes out the window and they are ALL loaded in, blowing up the device because there would be too many results to store in memory at one time.
So - your results are use case dependent. We use Swift High Order functions to massage our Realm data all the time - BUT, you have to go into it knowing the potential size of your data.
I think a good general rule of thumb is if you know the rough size of your data, it’s safe to use Swift functions. Otherwise, stick with Realm functions to massage the data.
let strings: [String] = ...
realm.objects(O.self).where { query in
let queryComponents = strings.map { string in query.name.ends(with: string) }
return queryComponents[1...].reduce(queryComponents[0]) { $0 || $1 }
}
My understanding is that the closure passed to where is only used to construct a predicate. From that perspective, it doesn’t seem like using map or reduce within that closure would be the same as using map or reduce on the Results.
I didn’t look closely enought at the code and saw the map and reduce but those are being used on the strings array and queryComponents so those will not affect Realm.
So just curious - what’s the use care for the code? Are you filtering realm for strings that match strings in the array?