|
Based on v35 (2011-05-15更新) - オリジナル 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" } );
Map/ReduceMongoDBは、Javascriptベースのサーバサイドでのmap/reduceをサポートしています。詳しくは、 map/reduce ドキュメント を参照してください。 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 )) );
eval の制限書き込みロック (write lock)eval はデフォルトではwrite lockを取得します。これは、 eval 内で、write lockする別のコマンドを実行できないことを意味します。たとえば、レプリカセットを走らせていて、新しいメンバーを追加したいとします。ドライバから、次のようなことを実行しようとするかもしれません。
db.eval("rs.add('ip-address:27017')");
繰り返しますが、 eval は現在のノードに対してwrite lockを取得します。そのため、この処理は動きません。なぜから、write lockされたノードが存在すると、新しいメンバーを追加できないからです。 正しい方法は、手動で新しいノードを追加することです。 rs.add は単に、 local.system.replSet コレクションにクエリを実行し、configオブジェクトを更新し、 replSetReconfig コマンドを実行します。これは、 eval を使わずにドライバから実行できます。
shardeval}}は、shardでも動かないことに注意してください。最終的にshardを使う予定なら、 {{eval は避けたほうがいいでしょう。 サーバサイドへのファンクションの保存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 にもっと例があります。 並列性に関するノートeval() は、実行中、mongodプロセス全体をブロックします。このため、このオペレーションはアトミックですが、他の処理中の操作は止まります。 並列性が必要なときには、eval()の代わりにmap/reduceを使ってください。 サーバ上のmongoシェルで .js ファイルを実行これは、バッチの管理処理を実行するのに適したテクニックです。 mongo をサーバ上で実行し、 localhost に接続します。 このコネクションはとても早く、遅延も少ないです。 db.eval() は他の操作をブロックするので、db.eval()よりもこの方法は使いやすいです。
|

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