|
Based on v26 最初にMongoはデータベースプロセス内でのコードの実行をサポートしています。 クエリー中の $where 句とファンクションfind() オペレーション用の通常形式のドキュメントスタイルのクエリに加え、SQLスタイルのWHERE句や完全なJavascriptファンクションを使うこともできます。 このクエリーモードを使うと、データベースはコレクションの中の一つずつのオブジェクトに対して、ファンクションを実行するか、条件を評価します。 文字列を指定した場合、"this"でオブジェクトを表します(下記の例を参照)。 Javascriptファンクションの場合、通常のJavascriptのシンタックスを使う事ができます。 Mongoシェル 内で次の4つの文は等価です。 db.myCollection.find( { a : { $gt: 3 } } );
db.myCollection.find( { $where: "this.a > 3" });
db.myCollection.find( "this.a > 3" );
db.myCollection.find( { $where: function() { return this.a > 3;}});
最初の文が一番好ましいです。 これは、わずかに他と比べ速いです。これは、オプティマイザが簡単に理解し使うインデックスを選ぶことができるからです。 データスタイルのfind条件と、ファンクションを混ぜることもできます。これは、データスタイルの表現が先に評価され、もしマッチしない場合には、その後の評価をする必要がないので、パフェーマンス面で有利になることがあります。加えて、データベースは、与えられた条件のフィールドから、インデックスを使用するかどうかを検討します。二つの形式を組み合わせるには、 クエリーオブジェクトに $where フィールドとして評価したいファンクションを渡します。たとえば、 db.myCollection.find( { active: true, $where: function() { return obj.credits - obj.debits < 0; } } );
db.myCollection.find( { active: true, $where: "this.credits - this.debits < 0" } );
db.eval() の使用db.eval() はデータベースサーバで(Javascriptで書かれた)ファンクションを実行するために使います。 簡単な例として、これは 3 + 3 をサーバで実行して取得します。 > db.eval( function() { return 3+3; } );
6
>
コレクション内のすべてのドキュメントで、指定したフィールド foo を削除したいとしましょう。クライアントサイドでやるとしたら以下のようになります。 function my_erase() {
db.things.find().forEach( function(obj) {
delete obj.foo;
db.things.save(obj);
} );
}
my_erase();
my_erase() をクライアント側で呼ぶと、コレクションのすべてのコンテンツがサーバからクライアントに転送され、また送り返されます。 db.eval(my_erase); 例> myfunc = function(x){ return x; };
> db.eval( myfunc, {k:"asdf"} );
{ k : "asdf" }
> db.eval( myfunc, "asdf" );
"asdf"
> db.eval( function(x){ return x; }, 2 );
2.0
評価中にエラーが起きた場合 (サーバ側でのnull pointer exceptionとか)、次の形で例外が投げられます。 { dbEvalException: { errno : -3.0 , errmsg : "invoke failed" , ok : 0.0 } }
Mongoの count() ファンクションと等価なことを eval() でする例です。 function mycount(collection) {
return db.eval( function(){return db[collection].find({},{_id:ObjId()}).length();} );
}
アトミックに、インクリメントといくつかの計算をするために、 db.eval() を使用する例です。 function inc( name , howMuch ){
return db.eval(
function(){
var t = db.things.findOne( { name : name } );
t = t || { name : name , num : 0 , total : 0 , avg : 0 };
t.num++;
t.total += howMuch;
t.avg = t.total / t.num;
db.things.save( t );
return t;
}
);
}
db.things.remove( {} );
print( tojson( inc( "eliot" , 2 )) );
print( tojson( inc( "eliot" , 3 )) );
サーバサイドへのファンクションの保存
system.js という特別なコレクションがあります。これに、Javascriptのファンクションを繰り返し使うために保存することができます。ファンクションを保存するためには、 db.system.js.save( { _id : "foo" , value : function( x , y ){ return x + y; } } );
_id はファンクションの名前です。データーベース毎にユニークです。 一度これをしたら、 foo をどのJavascriptからでも呼ぶことができます。 (db.eval, $where, map/reduce) http://github.com/mongodb/mongo/tree/master/jstests/storefunc.js にもっと例があります。 Map/ReduceMongoDBは、サーバ上でのJavascriptベースのmap/reduceをサポートしています。 map/reduce ドキュメント に情報があります。 並列性に関するノートeval() は、実行中、mongodプロセス全体をブロックします。このため、このオペレーションはアトミックですが、他の処理中の操作は止まります。 並列性が必要なときには、eval()の代わりにmap/reduceを使ってください。 |

IF YOU HAVE A QUESTION, POST IT TO THE USER GROUP.
These pages are fine for comments, but for questions, your best bet will always be the MongoDB User Group. blog comments powered by Disqus