I'm kind of confused on how to use closures in mongodb shell.
I want to create a function that i can use exclusively during development to quickly look up a document by a part of it's _id
.
The function should return a $where
selector that does the necessary matching.
I wanted to write it like this:
var id = function(pattern, selector) {
return Object.extend({
$where: function() {return (this._id + "").indexOf(pattern) != -1;}
}, selector);
};
But when i try it i get the following error:
db.mycollection.find(id("ab1"));
error: {
"$err" : "JavaScript execution failed: ReferenceError: pattern is not defined near ').indexOf(pattern) ' ",
"code" : 16722
}
Invoking $where
manually does seem to work oddly enough:
id("ell").$where.call({_id: "hello"}); // true
I could only think of this as a solution to make it work, but this is obviously terrible.
To clarify: This method with new Function
works fine, but i don't like it as the above method should work as well.
var id = function(pattern, selector){
return Object.extend({
$where: new Function("return (this._id + '').indexOf('" + pattern + "') != -1;")
}, selector);
};
It appears that the MongoDB shell serializes (in this case, string-ifies) $where
function objects in order to send them to the server.
A function in JavaScript is much more than its functional code -- it's part of a closure, which includes both the function code itself and the function's variable referencing environment for accessing non-local variables. After the function is serialized, it gets unserialized and executed with different referencing environment. When the function tries to reference pattern
, it's asking for pattern
in a totally different referencing environment, which does not have a pattern
variable.
That's why your literal string function works. That function contains the actual value of pattern
, not the variable identifier pattern
.
See this MongoDB bug, which explains:
That would work if the function was being evaluated locally, but the closure isn't sent over automatically.
In babble it used to be, but not in the shell.
This suggests that your code may work outside of the shell, but I don't know enough about Mongo internals to say for sure.