2013-03-25 75 views
3

當我使用在nodejs中的「$ where」子句中傳遞的函數查詢我的數據庫時,它總是會返回db中的所有文檔。

例如,如果我這樣做

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

還給了我所有的文件。 相反,如果我做

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

是真正執行的功能,而這個代碼不返回任何文檔。

問題是,如果我在字符串中轉換我的函數上下文的bindinds被刪除,我需要他們更復雜的查詢。例如:

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

這是正常行爲嗎?我如何解決我的問題? 請原諒我可憐的英語!

+2

雖然它可能會很酷,如果這將工作的方式,你建議,它不會。你想要什麼類型的查詢?使用'$ where'通常被認爲是最後的選擇,因爲它執行的方式和結果的性能。如果你還沒有閱讀(http://docs.mongodb.org/manual/reference/operator/where/)。 – WiredPrairie 2013-03-25 11:15:21

回答

4

首先,請記住,$where運營商應該幾乎從不使用的原因解釋here(功勞@WiredPrairie)。

回到你的問題,即使在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的本地蒙戈驅動程序之處在於它不會自動序列您在查詢對象提供一個js函數的外殼行爲不同,而是它可能完全丟棄條款。這將使您等於timetables.find({}),這將返回集合中的所有文檔。

+0

> db.test.find({$ where:function(){return this.a == 42}}) 當42的值爲Dynamic時,不能使用上面的代碼。 使用這個時仍然會出現同樣的錯誤。 – 2017-08-30 11:42:42

1

上下文將始終是mongo數據庫的上下文,因爲函數在那裏執行。沒有辦法在兩個實例之間共享上下文。你必須重新思考你的方式,並提出一個不同的策略。

0

這是它應該如何。驅動程序不會將客戶端代碼轉換爲mongo函數javascript代碼。

0

我假設您使用Mongoose來查詢您的數據庫。

如果您看看實際的查詢對象實現,您會發現只有字符串where prototype的有效參數。

使用where子句時,應該將其與標準運算符(如gt,lt)一起使用,該運算符在where函數創建的路徑中進行操作。

請記住,Mongoose查詢,如在Mongo中,舉例來說,您可能希望以更具描述性的方式重新考慮您的查詢規範。

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 } ]) 
} 
2

這一個是作品對我來說,只要嘗試將查詢作爲字符串存儲在一個變量中,然後將查詢字符串中的變量連接起來,就可以將您的變量連接到查詢字符串中,

VAR local_var = 42

VAR查詢= 「{$其中:函數(){返回this.a == 」+ local_var +「}}」

db.test.find(查詢)

2

將查詢存儲到varibale中,並在查找查詢中使用該變量。它的工作.....:D

+1

是的,絕對是它的工作,我試過同樣的方法 – 2017-08-30 11:33:37