10

nodejsの「$where」句で渡された関数を使用してデータベースにクエリを実行すると、常にデータベース内のすべてのドキュメントが返されます。

たとえば、私がする場合

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

これは正常な動作ですか?どうすれば問題を解決できますか?英語が下手で失礼します!

4

7 に答える 7

7

まず、ここで$where説明されている理由から、オペレーターを使用することはほとんどないことを覚えておいてください(クレジットは@WiredPrairieに送られます)。

あなたの問題に戻ると、あなたが採用したいアプローチは、mongodbシェル($where演算子で裸のjs関数を明示的に許可する)でも機能しません。オペレーターに提供されたjavascriptコードは$where、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ドライバーは、クエリオブジェクトで提供するjs関数を自動的にシリアル化せず、代わりに句を完全に削除するという点で、シェルとは異なる動作をするように見えます。timetables.find({})これにより、コレクション内のすべてのドキュメントを返すのと同等の機能が残ります。

于 2013-03-25T12:40:24.663 に答える
4

これは私にとってはうまくいきます。クエリを文字列として1つの変数に格納してから、変数をクエリ文字列に連結してみてください。

var local_var = 42

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

db.test.find(query)

于 2017-08-30T11:13:45.950 に答える
2

クエリを変数に保存し、その変数を検索クエリで使用します。それは動作します.....:D

于 2017-08-30T11:32:10.197 に答える
1

関数はそこで実行されるため、コンテキストは常にmongoデータベースのコンテキストになります。2つのインスタンス間でコンテキストを共有する方法はありません。クエリの方法を再考し、別の戦略を考え出す必要があります。

于 2013-03-25T10:46:17.007 に答える
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 } ])
}
于 2014-04-04T13:19:30.963 に答える
0

これが本来あるべき姿です。ドライバーは、クライアントコードをmongo関数のjavascriptコードに変換しません。

于 2013-03-25T11:07:46.417 に答える
0

データベースのクエリにMongooseを使用していると想定しています。

実際のQueryオブジェクトの実装を見ると、 whereプロトタイプの有効な引数は文字列だけであることがわかります。

where句を使用する場合は、where関数によって作成されたパスで動作するgt、ltなどの標準演算子と一緒に使用する必要があります。

Mongoの場合のように、Mongooseクエリは例として、より説明的な方法でクエリ仕様を再検討することをお勧めします。

于 2013-03-25T11:19:48.343 に答える