New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Searches using $or don't work correctly on the client #1089

Closed
johnston opened this Issue May 24, 2013 · 6 comments

Comments

Projects
None yet
3 participants
@johnston
Contributor

johnston commented May 24, 2013

I have experienced an issue conducting a search using regular expressions and $or.

The search I'm trying to make work is:

r = new RegExp '^' + preg_quote(q), 'i'
Contacts.find {'$or': [ {firstName: r}, {lastName: r} ] }

i.e. Give me all the contacts whose first or last name starts with "A".

I've created a repo showing this here: https://github.com/johnston/meteor-mongo-or-bug

After launching the app mrt and visiting http://localhost:3000, what should happen is clicking each letter causes the following names to appear:

  • A = Albert Einstein
  • B = Bruce Willis & David Brown
  • C = Chris Rock

but what actually happens is when you click each letter, you might get one name appearing but never all three.

The server correctly outputs:

Filtering by "A" gives 1 results: Albert Einstein
Filtering by "B" gives 2 results: Bruce Willis, David Brown
Filtering by "C" gives 1 results: Chris Rock

But in the browser's console you get:

Filtering by "A" gives 0 results: 
Filtering by "B" gives 0 results:
Filtering by "C" gives 0 results:

Now, just add a single blank line to end of the test.html and save it. This triggers a page reload. This time the last letter click has the correct result, but none of the others do.

It works on the first name alone if you change it to:

Contacts.find { firstName: r }

(to do this using the repo, open an editor and comment out line 11 and 51. Comment in line 14 and 54. It now works.)

I can only assume from this there is some issue with $or searches?

@awatson1978

This comment has been minimized.

Contributor

awatson1978 commented May 24, 2013

Here's how I do my $or lists on the client side:

return CustomerAccounts.find({
            $or: [
                {'FirstName': { $regex: Session.get('user_search_term'), $options: 'i' }},
                {'LastName':  { $regex: Session.get('user_search_term'), $options: 'i' }}
            ]
        },{limit: 20});
@johnston

This comment has been minimized.

Contributor

johnston commented May 24, 2013

@awatson1978 I have tried that against my test code but sadly get the same result.

Works on the server but not on the client.

@johnston

This comment has been minimized.

Contributor

johnston commented May 24, 2013

I should add: If you publish a collection that returns every Contact it works as well. Obviously this isn't efficient but perhaps points to a problem in the client tracking what Contacts are available?

@awatson1978

This comment has been minimized.

Contributor

awatson1978 commented May 24, 2013

Yeah, I was just going to mention that. As for efficiency, I'm not sure
it's that obviously inefficient. It boils down to goals and what you're
trying to automate and save time on; and for many situations, it's best to
return a block of results and then do filtering on the client side. Here's
a question for you: are you trying to implement a search or a filter with
this regex?

Right now, the way you've got it implemented, you're doing both. And whats
probably happening is the search scope is too narrow due to a timing issue.
Put another way, the filtered page is getting rendered before the results
are published. Or the combination of both a search and a filter is
resulting in a null set, instead of an identity set. You might try
insisting on a page redraw with a Meteor.flush():

Template.searchbox.events({
'click .links a': function(e) {
e.preventDefault();
Session.set('search', e.target.innerHTML);
Meteor.flush();
}
});

Also, while your $or searches are very similar on both the server side and
the client side, they are not actually the same. The client side has a
reactive variable in it, whereas the server has a regular variable. That
reactive variable is going to fire before the server has a chance to return
data. My guess is that line 48 is probably where things are going awry:

r = new RegExp '^' + preg_quote(Session.get('search')), 'i'

On Fri, May 24, 2013 at 3:08 PM, Stuart Johnston
notifications@github.comwrote:

I should add: If you publish a collection that returns every Contact it
works as well. Obviously this isn't efficient but perhaps points to a
problem in the client tracking what Contacts are available?


Reply to this email directly or view it on GitHubhttps://github.com//issues/1089#issuecomment-18423292
.

@glasser

This comment has been minimized.

Member

glasser commented May 24, 2013

This is a bug in interactions between $or/$and/etc and RegExp objects. Changing your code to

r = {$regex: ('^' + preg_quote(q)), $options: 'i'}

is a workaround. Take a look at packages/mongo-livedata/mongo_driver.js in Meteor.Collection._rewriteSelector: there's an XXX comment about how converting RegExp objects to {$regex,$options} should be done inside $or but it isn't being done now. (Various places inside Meteor's Mongo driver need to serialize queries to JSON and RegExps don't serialize well.)

Would happily take a pull request to fix this.

johnston added a commit to johnston/meteor that referenced this issue May 24, 2013

Translate RegEx in lower levels of $and/$or/$nor selectors
Recurses over $and/$or/$nor selectors to translate RegEx into {$regex,
$options}.

Resolves meteor#1089
@johnston

This comment has been minimized.

Contributor

johnston commented May 24, 2013

@glasser Super thanks. That fixes it perfectly. pull-request sent.

glasser added a commit that referenced this issue May 24, 2013

Translate RegEx in lower levels of $and/$or/$nor selectors
Recurses over $and/$or/$nor selectors to translate RegEx into {$regex,
$options}.

Resolves #1089

@glasser glasser closed this May 24, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment