Parse.com finding partial string in an array
I am trying to find a Parse.com field that is an array for a partial string.
When the field is in String format, I can do the following:
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.searchResults removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.busnumber contains[c] %@", searchText];
self.searchResults = [NSMutableArray arrayWithArray:[self.objects filteredArrayUsingPredicate:predicate]];
This works, however the new field I want to find is an array. It works when I change it to the following:
PFQuery * query = [PFQuery queryWithClassName:@"Bus"];
[query whereKey:@"route" equalTo:[NSString stringWithFormat:@"%@", searchText]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(@"Objects: %@", objects);
if (error)
{
NSLog(@"ERROR: %@", error.localizedDescription);
}
else
{
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:objects];
[self.searchDisplayController.searchResultsTableView reloadData];
}}];
However, I need the exact string for this.
I want to be able to search for parts of a string though, when I change it to:
[query whereKey:@"route" containsString:[NSString stringWithFormat:@"%@", searchText]];
I get:
[Error]: $regex only works on string fields (Code: 102, Version: 1.7.4)
Any ideas? Thank:)
source to share
What you tried is rational, but string qualifiers in PFQuery only work on strings.
I've seen this thread a lot on SO: PFQuery only provides basic comparisons for simple attributes. To do anything else, you need to query the supernet and perform application-level computations to reduce the superset to the desired set. This is expensive for two reasons: speed / space at the application level, network transfer add-on.
The first expense is mitigated and the second expense is eliminated using a cloud-based feature to reduce the add-on layer at the application level. If you still need add-in records on the client, consider moving this request to the cloud.
Specifically for this question, here is what I think the cloud function will resemble:
// very handy to have underscore available
var _ = require('underscore');
// return Bus objects whose route array contains strings which contain
// the passed routeSubstring (request.params.routeSubstring)
Parse.Cloud.define("busWithRouteContaining", function(request, response) {
// for now, don't deal with counts > 1k
// there a simple adjustment (using step recursively) to get > 1k results
var query = new Parse.Query("Bus");
query.find().then(function(buses) {
var matching = _.select(buses, function(bus) {
var route = bus.get("route");
var routeSubstring = request.params.routeSubstring;
return _.contains(route, function(routeString) {
return routeString.includes(routeSubstring);
});
});
response.success(matching);
}, function(error) {
response.error(error);
});
});
If you decide to shortcut on the client and need help with the code, I can change it. This is going to be a fairly straightforward jump to predicateWithBlock:
with a block that iterates over an array attribute and checks rangeOfString:
on each.
source to share