高度なクエリー

based on v73

最初に

MongoDBには多くの機能を持ったリッチなクエリーがあります。このページはその中のいくつかの機能を紹介します。

MongoDBのクエリはJSON形式で表現します。データベースに保存しているドキュメントにとても似ています。  たとえば、

// i.e., select * from things where x=3 and y="foo"
db.things.find( { x : 3, y : "foo" } );

このページに出てくるオペレータはすべて同じクエリ内で組み合わすことができることに注目してください。たとえば、jが3ではなく、kが10より大きいすべてのドキュメントを探すクエリは、

db.things.find({j: {$ne: 3}, k: {$gt: 10} }); 

フィールドの中の一部を取得

findオペレーションはデフォルトでは、document/objectのすべてのオブジェクトが返されます。しかし、指定した一部のフィールドだけを返すこともできます。 _id フィールドは常に返されることに注意してください。

// select z from things where x=3
db.things.find( { x : 3 }, { z : 1 } );

また、サイズが大きいとわかっている特定のフィールドを外すこともできます。

// mongodbに関するすべてのポストからcommentsを除いて取得
db.posts.find( { tags : 'mongodb' }, { comments : 0 } );

条件オペレータ : <, <=, >, >=

クエリの中で、多い、少ない、という比較のためには以下の特別な形式を使ってください。

db.collection.find({ "field" : { $gt: value } } ); // 大きい : field > value 
db.collection.find({ "field" : { $lt: value } } ); // 小さい : field < value 
db.collection.find({ "field" : { $gte: value } } ); // 以上 : field >= value 
db.collection.find({ "field" : { $lte: value } } ); // 以下 : field <= value 

例:

db.things.find({j : {$lt: 3}}); 
db.things.find({j : {$gte: 4}}); 

範囲指定するために以下を組み合わせることができます。

db.collection.find({ "field" : { $gt: value1, $lt: value2 } } ); // value1 < field < value 

条件オペレータ : $ne

不等号には、$neを使ってください。

db.things.find( { x : { $ne : 3 } } ); 

条件オペレータ : $in

$in オペレータは、SQLの IN に似ています。配列でマッチする組を指定できます。

db.collection.find( { "field" : { $in : array } } ); 

いくつかの例を見てみましょう。 things コレクションから、キー'j'の値によってサブセットを取得します。

db.things.find({j:{$in: [2,4,6]}}); 

updates コレクションはソーシャルネットワーク形式のニュースアイテムと仮定します。ここで、友人の最新の10個の最近のアップデートを取得したいとします。

db.updates.ensureIndex( { ts : 1 } ); // ts == timestamp 
var myFriends = myUserObject.friends; // これは友人のデータベース参照を取得すると仮定しましょう。
var latestUpdatesForMe = db.updates.find( { user : { $in : myFriends } } ).sort( { ts : -1 } ).limit(10); 

条件オペレータ : $nin

$nin オペレータは、 $in に似ていますが、指定したフィールドに、指定した配列のどの値も含まれていないオブジェクトを選択します。たとえば、

db.things.find({j:{$nin: [2,4,6]}}); 

{j:1,b:2} にマッチしますが、 {j:2,c:9} にはしません。

条件オペレータ : $mod

$mod オペレータは、where条件の中で、速く、余り、を求めるためのものです。例えば、以下の$whereクエリーで、

db.things.find( "this.a % 10 == 1") 

これは以下のように置き換えられます、

db.things.find( { a : { $mod : [ 10 , 1 ] } } ) 

条件オペレータ : $all

$all オペレータは、 $in に似ていますが、指定した配列すべてがマッチする必要があります。例えば、

{ a: [ 1, 2, 3 ] }

これは以下にマッチします。

db.things.find( { a: { $all: [ 2, 3 ] } } );

しかしこれはしません、

db.things.find( { a: { $all: [ 2, 3, 4 ] } } );

条件オペレータ : $size

$size オペレータは、指定された配列の要素のサイズにマッチします。次の例は、 {a:["foo"]} にマッチします。なぜならこの配列は1つの要素だからです。

db.things.find( { a : { $size: 1 } } ); 

条件オペレータ : $exists

フィールドが存在するか(またはしないか)をチェックします。

db.things.find( { a : { $exists : true } } ); // 存在する場合オブジェクトを返します。
db.things.find( { a : { $exists : false } } ); // 存在しない場合 

正規表現

データベースのクエリ表現で正規表現を使えます。

db.customers.find( { name : /acme.*corp/i } ); 

/^prefix/ のような、先頭一致をするだけの単純なクエリでは、データベースは可能であればインデックスを使います(多くのSQLデータベースが、 LIKE 'prefix%' に対してインデックスを使うのと似ています)。これは、 i (case-insensitivity) のオプションを付けてないときだけです。

1.3.3での新機能

データベースは、とても単純なprefixクエリーをrangeクエリーに置き換えます。 {/^a/}} と /^a./* と * /^a.$/ はすべて等価ですが、その置換えは最初のでだけ起きるので、そのフォーマットを使ってください。

配列内の値

colors フィールドの中の"red"を探すには、

db.things.find( { colors : "red" } ); 

"colors"が検索されるとき、もし配列だった場合、配列の各値が調べられます。   このテクニックは、 これと一緒に 以下の組み込みオブジェクトで一緒に使うことができます。

条件オペレータ: $elemMatch

バージョン1.3.1以上が必要です。

$elemMatch は、配列の中の要素が指定した条件にマッチするかをチェックします。

> t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )  
{ "_id" : ObjectId("4b5783300334000000000aa9"), 
"x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ] 
} 

一つの配列内の要素すべてが、指定した条件にマッチする必要があることに注意してください。 つまり、x配列内の異なった要素にマッチできる下記のクエリーは、意味的に違います。

> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } ) 

組み込みオブジェクト内の値

例えば、 postings コレクション内の、組み込みのauthor オブジェクトから、 author.name=="joe" を探す場合、

db.postings.find( { "author.name" : "joe" } ); 

メタオペレータ: $not

$not メタオペレータは、通常のオペレータを否定するときに使います。たとえば、

db.customers.find( { name : { $not : /acme.*corp/i } } );
db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );

Javascript 表現と $where

ここまでで説明してきた構造化されたクエリーに加え、Javascriptの形式でクエリーを指定することもできます。これをするためには、Javascriptを含む文字列を find() に渡します。または、そのような文字列をオブジェクトのmemberである $where にアサインします。 データベースは、オブジェクトのスキャンにそのJavascriptを使い評価します。評価の結果が true の場合には、オブジェクトはクエリーの結果として返されます。

たとえば、次の各式は、すべての同じことをします。

db.myCollection.find({ a : { $gt: 3 } } );
db.myCollection.find( { $where: "this.a > 3" } );
db.myCollection.find("this.a > 3");

f = function() { return this.a > 3; } db.myCollection.find(f);

Javascriptの実行は、このページで紹介したネイティブのオペレーターよりも遅いですが、とても柔軟性があります。 詳しい情報は、 サーバ側でのコードの実行 を参照してください。

sort()

sort() はSQLでの、ORDER BYに似ています。これは、結果を特定の順序で返すことを要求します。 sort() に、希望する順を示すキーパターンを渡します。

db.myCollection.find().sort( { ts : -1 } ); // tsの降順でソートします

sort() は {[limit()}} と組み合わせて使えます。実際には、指定したキーパターンに関連するインデックスがない場合、 limit は、インデックスが使われないときソートされた件数を制限するので、推奨されます。

limit()

limit() は、MySQLのLIMITに似ています。 これは、取得する最大の件数を指定します。 最高のパフォーマンスのためには、可能な限りいつでも limit() をつけてください。 そうしないと、データベースは、処理で必要な件数よりも多くの結果を返してしまうことがあります。

db.students.find().limit(10).forEach( function(student) { print(student.name + "<p>"); } ); 

skip()

skip() で、返される結果がどのオブジェクトから始めるかを指定します。これは、 "ページング" を実装したいときに便利です。 以下は、JavaScriptアプリケーションでどう使われかの例です。

function printStudents(pageNumber, nPerPage) { 
print("Page: " + pageNumber); 
db.students.find().skip((pageNumber-1)*nPerPage).limit(nPerPage).forEach( function(student) { print(student.name + "<p>"); } ); 
} 

snapshot()

クエリーをsnapshotモードで使うことを明示します。snaphostモードは、クエリー実行中、最初から最後まで、(たとえオブジェクトが更新されても)重複した値や、存在しないオブジェクトを返さないことを保証します。もし、クエリー実行中に、オブジェクトが追加、削除された場合には、たとえばsnapshotモードでも、それらのオブジェクトは返されるかも(返されないかも)しれません。

短いクエリのレスポンス (1MB以下)では、常に事実上snapshotなことに注意してください。

現在のところ、 snapshotモードは、sortや明示的なhintを使った場合、使用されません。

count()

count() メソッドは、指定したクエリにマッチするオブジェクトの数を返します。これは、MongoDBサーバ上で特別に最適化され実行されるので、クライアントサイドでするより速いし効率的です。

nstudents = db.students.find({'address.state' : 'CA'}).count(); 

以下の方法で同じ結果を取得することができますが、以下はすべてのドキュメントをクライアント側のメモリに入れてからカウントするので、遅いし非効率的です。しないでください。

nstudents = db.students.find({'address.state' : 'CA'}).toArray().length; // VERY BAD: 遅いし、多くのメモリを使います

skip()とlimit()を使うクエリでも、デフォルトではcountの結果はそれらを無視します。skipやlimitをした結果の値が必要な場合には、count(true)を使ってください。

n = db.students.find().skip(20).limit(10).count(true);

group()

group() メソッドは、SQLの GROUP BY に似ていますが、 group() はもっと柔軟です。 任意のreductionのためのオペレーションを指定することができます。 詳しくは、 開発者ガイド集約 セクションを見てください。

その他

* Optimizing Queries (including explain() and hint())


Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

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