hnandarusdy
hnandarusdy

Reputation: 452

searching in mongo specifically

I have a question, lets say I have a collection called contact :

[
    {"firstName": "Adam", "lastName":"Peter", "email":"[email protected]"},
    {"firstName": "Adam", "lastName":"John", "email":"[email protected]"},
    {"firstName": "Adam", "lastName":"Petkovic", "email":"[email protected]"}
]

What I want is to search specifically, for example: I want to search "Adam peter" then I want to have a result of the first one ONLY which has Adam and peter.

I use meteor + mongo + react for my application.

Any suggestion / recommendation would be high appreciated.

Thanks for all the answers, but probably I need to ask more specific in order to get more appropriate answer.

Scenarios:

So:

Upvotes: 0

Views: 76

Answers (3)

Nathan Webb
Nathan Webb

Reputation: 457

Assuming that the rules that you are applying are:

  • If a single word, then that could match any field
  • two words mean "firstname surname"

In that case, you can't use text indices, but instead need to do some work before the mongo search.

First, split the words on whitespace, and then determine if there are one or two words. If there is one word, check that against all fields. If there are two, then only check the first word against the first name, and the second against the lastname.

// assuming input is in variable call 'term'
var words = term.trim().split(/\s+/) || [];

if(words.length === 0) {
    return;
}
var first = new RegExp(words[0], 'i');
if(words.length === 2) {
    var second = new RegExp(words[1], 'i');
    return Contact.find({firstName: first, lastName: second});
else if(words.length === 1) {
    return Contact.find({$or: [ {firstName: first}, {lastName: first}, {email: first}]})
}

Also, depending on how large your collection is, it might be better to wrap this up into a Meteor method, so that the search takes place on the server. Otherwise, you will have to publish the whole collection on the client to be able to do the search. That might be fine for a small collection though.

UPDATE:

Based on your examples, I think your rules are: 1. Search terms are combined with AND operator (e.g. Adam Pet returns two rows, not three). 2. Search terms use regular expression matching (Pet matches even though it's not any of the words).

Rule 2 means that text indices won't work, so you will need to build up a complex regex query document using $and and $or for each item:

// assuming input is in variable call 'term'
var words = term.trim().split(/\s+/) || [];
var query = {
    "$and": []
};
words.forEach(function(token) {
    var reg = new RegExp(token);
    var innerQ = {"$or": [ {firstName: reg}, {lastName: reg}, {email: reg}]};
    query["$and"].push(innerQ);
});
return Contact.find(query);

Upvotes: 0

ryanhex53
ryanhex53

Reputation: 727

The query in MongoDB is case sensitive, if you want to query contact by ignoring case, you should use a regular expression, but it may not efficient.

db.contact.findOne({firstName: /^adam$/i, lastName: /^peter$/i})

it will much better if you always save these name value in lowercase, and query in lowercase

db.contact.findOne({firstName: 'adam', lastName: 'peter'})

Upvotes: 0

Sudheer Jami
Sudheer Jami

Reputation: 757

From the answer here, below query should work fine.

db.contacts.find( { firstName: /^Adam$/i, lastName: /^peter$/i });

Upvotes: 1

Related Questions