Mongodb $其中查询始终与nodejs一致

时间:2013-03-25 10:42:41

标签: node.js mongodb

当我使用nodejs中“$ where”子句中传递的函数查询我的数据库时,它总是返回db中的所有文档。

例如,如果我这样做

var stream = timetables.find({$where: function() { return false; }}).stream();

它将所有文件归还给我。 相反,如果我做

var stream = timetables.find({$where: 'function() { return false; }'}).stream();

该函数实际执行,此代码不返回任何文档。

问题是,如果我在字符串my function中转换上下文的绑定被删除,我需要它们来进行更复杂的查询。例如:

var n = 1;
var f = function() { return this.number == n; }
var stream = timetables.find({$where: f.toString()}).stream();
// error: n is not defined

这是正常行为吗?我怎样才能解决我的问题? 请原谅我的英语不好!

7 个答案:

答案 0 :(得分:4)

首先请注意,$where运算符几乎不应该用于here解释的原因(功劳归于@WiredPrairie)。

回到你的问题,你想采取的方法即使在mongodb shell中也是行不通的(mongodb shell明确允许使用$where运算符的裸js函数)。提供给$where运算符的javascript代码在mongo服务器上执行,无法访问封闭环境(“上下文绑定”)。

> db.test.insert({a: 42})
> db.test.find({a: 42})
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> db.test.find({$where: function() { return this.a == 42 }}) // works
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> var local_var = 42
> db.test.find({$where: function() { return this.a == local_var }})
error: {
    "$err" : "error on invocation of $where function:\nJS Error: ReferenceError: local_var is not defined nofile_b:1",
    "code" : 10071
}

此外,看起来node.js本机mongo驱动程序的行为与shell不同,因为它不会自动序列化您在查询对象中提供的js函数,而是可能完全删除该子句。这将为您留下相当于timetables.find({})的内容,它将返回集合中的所有文档。

答案 1 :(得分:2)

这个适用于我,只是尝试将查询作为字符串存储在一个变量中,然后在查询字符串中连接您的变量,

  

var local_var = 42

     

var query =" {$ where:function(){return this.a ==" + local_var +"}}"

     

db.test.find(查询)

答案 2 :(得分:2)

将查询存储到varibale中,并在查找查询中使用该变量。它有效.....:D

答案 3 :(得分:1)

上下文将始终是mongo数据库的上下文,因为该函数在那里执行。无法共享两个实例之间的上下文。你必须重新思考你的查询方式并提出不同的策略。

答案 4 :(得分:1)

您可以使用包装器传递基本的JSON对象,即。 (原谅咖啡脚本):

# That's the main wrapper.
wrap = (f, args...) ->
  "function() { return (#{f}).apply(this, #{JSON.stringify(args)}) }"

# Example 1
where1 = (flag) ->
  @myattr == 'foo' or flag

# Example 2 with different arguments
where2 = (foo, options = {}) ->
  if foo == options.bar or @_id % 2 == 0
    true
  else
    false

db.collection('coll1').count $where: wrap(where1, true), (err, count) ->
  console.log err, count

db.collection('coll1').count $where: wrap(where2, true, bar: true), (err, count) ->
  console.log err, count

您的功能将按以下方式传递:

function () {
    return (function (flag) {
        return this.myattr === 'foo' || flag;
    }).apply(this, [true])
}

...和示例2:

function () {
    return (
        function (foo, options) {
            if (options == null) {
                options = {};
            }
            if (foo === options.bar || this._id % 2 === 0) {
                return true;
            } else {
                return false;
            }
        }
    ).apply(this, [ true, { "bar": true } ])
}

答案 5 :(得分:0)

这是应该的样子。驱动程序不会将客户端代码转换为mongo函数javascript代码。

答案 6 :(得分:0)

我假设您正在使用Mongoose来查询您的数据库。

如果您查看实际的Query对象实现,您会发现只有 strings where prototype的有效参数。

当使用where子句时,您应该将它与标准运算符一起使用,例如gt,lt在where函数创建的路径中运行。

请记住Mongoose查询,例如在Mongo中,例如,您可能想以更具描述性的方式重新考虑您的查询规范。