Chris
Chris

Reputation: 14198

How to use an external variable in MongoDB 'where' query via Javascript?

I have a MongoDB query that searches all properties for a value defined in the search variable. It works the following way:

 db.collection.findOne({
                $where: function() {
                    var search = 'searchstring';
                    for (var key in this) {
                        if (this[key] === search) {
                          return true;
                        }
                        return false;
                    }
                }
            });

However, I would like to define the search variable outside the query.

But when I do so, I get an error that it is not referenced (i.e. scoping issue):

"ReferenceError: search is not defined near '[key] === search

How can I use or pass the variable to the query filter?

Upvotes: 5

Views: 3946

Answers (3)

Aida Drogan
Aida Drogan

Reputation: 159

You can try something like this:

var searchstring = 'whatever';
var params = {};
params.$where = 'function() {' +
    'var search = "' + searchstring + '";' +
    'for (var key in this) {' +
        'if (this[key] === search) {' +
            'return true;' +
        '}' +
        'return false;' +
    '}' +
'}';
db.collection.findOne(params);

(Stringify your function and concat with external variable)

Worked for me via mongoose

Upvotes: 11

BatScream
BatScream

Reputation: 19700

search is a variable that you define in your client, may be the shell, or any client API.

The function that you define for the $where clause, will not be executed on the client side, but on the mongodb server. so, when the function is being interpreted in the server side and it looks for the search variable, it was never defined on the server and hence you get the error.

In your case, you want the variable search, to be replaced with its content, by the client, before being executed on the server. And this is not possible, unless you build the function content itself in the client side.

The client never really interprets anything you write inside the anonymous function. The server does. The error you see is from the server. You can validate it by firing this query and looking onto the server logs:

2015-12-22T19:03:44.011-0800 I QUERY    [conn1] assertion 16722 ReferenceError:
searc is not defined
    at _funcs1 (_funcs1:1:39) near 's.key === searc){retu'  ns:test.t query:{ $w
here: function (){if(this.key === searc){return true}} }

There is a better way to write what you wish to achieve using the $exists operator.

var search = "title";
var find = {};
find[search] = {$exists:true};
db.collection.findOne(find);

This works, because, you build the query parameter fully on the client side, before passing it on to the findOne() method.

Upvotes: 1

Volodymyr Synytskyi
Volodymyr Synytskyi

Reputation: 4055

You can solve this problem using mongodb map reduce and scope functionality. Scope allows you to pass variables into map reduce job.

function map() {
    for (var key in this) {
        if (this[key] === search) {
            return emit(this._id, this);
        }
    }
}

function reduce(key, values) {
    return values[0];
}


db.collection.mapReduce(map, reduce, {
        out: {inline: 1},
        scope: {
            search: 'searchstring'
        }
    }
);

Upvotes: 1

Related Questions