Ramsy de Vos
Ramsy de Vos

Reputation: 1072

parse.com search for partial string in array

I'm trying to search a Parse.com field which 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 search in is an Array. It works when I change the 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, but 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? Thanks :)

Upvotes: 3

Views: 1202

Answers (1)

danh
danh

Reputation: 62676

What you've attempted is rational, but the string qualifiers on PFQuery work only on strings.

I've seen this theme frequently on SO: PFQuery provides only basic comparisons for simple attributes. To do anything more, one must query for a superset and do app level computation to reduce the superset to the desired set. Doing so is expensive for two reasons: app-level compute speed/space, and network transmission of the superset.

The first expense is mitigated and the second expense is eliminated by using a cloud function to do the app level reduction of the superset. Unless you need the superset records on the client anyway, consider moving this query to the cloud.

Specific to this question, here's what I think the cloud function would 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's 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 do decide to perform the reduction on the client and need help with the code, I can edit that in. It will be a pretty simple switch to predicateWithBlock: with a block that iterates the array attribute and checks rangeOfString: on each.

Upvotes: 2

Related Questions