高度なクエリー

based on v117 (2010-12-01更新) - オリジナル

最初に

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} }); 

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

[フィールドの中の一部を取得] 参照

条件オペレータ

<, <=, >, >=

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

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 

$all

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

{ a: [ 1, 2, 3 ] }

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

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

しかしこれはしません、

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

一つの配列は、 $all 条件で指定したよりも多くの要素を持つことができます。。 $all で指定したものがすべてマッチする必要があります。

$exists

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

db.things.find( { a : { $exists : true } } ); // 存在する場合オブジェクトを返します。
db.things.find( { a : { $exists : false } } ); // 存在しない場合 
現在のところ、 $exists はインデックスを使いません。 $exists 以外のフィールドはインデックスを使います。

$mod

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

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

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

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

$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} にはしません。

$nor

$nor オペレータでは、 boolean または式が扱えます。 $nor に式のリストを渡します。

$or

$or オペレータを使うと、booleanまたは式をクエリで使うことができます。 $or に式のリストを渡します。

MongoDB 1.5.3から

単純に、

db.foo.find( { $or : [ { a : 1 } , { b : 2 } ] } )

他のフィールドと

db.foo.find( { name : "bob" , $or : [ { a : 1 } , { b : 2 } ] } )

$or 操作は、それぞれの条件にマッチするものを取得し、結果から重複したものを取り除きます。 $or での数々の最適化が 1.8 で予定されています。 このスレッド を参照。

$or はネストできません。

$size

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

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

$size で範囲指定をすることはできません(たとえば、 1つ以上の要素を持つ配列)。 範囲指定が必要な場合は、 size フィールドを自分で作り要素を加えるたびにインクリメントしてください。

$type

$type オペレータは、値の BSON のタイプにマッチします.

db.things.find( { a : { $type : 2 } } ); // stringにマッチ
db.things.find( { a : { $type : 16 } } ); // intにマッチ

指定できるタイプは:

Type Name Type Number
Double 1
String 2
Object 3
Array 4
Binary data 5
Object id 7
Boolean 8
Date 9
Null 10
Regular expression 11
JavaScript code 13
Symbol 14
JavaScript code with scope 15
32-bit integer 16
Timestamp 17
64-bit integer 18
Min key 255
Max key 127

BSONの一般的なタイプについては、 http://www.bsonspec.org を見てください。

正規表現

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

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

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

/^a//^a./* と * /^a.$/ は等価です。またインデックスも同じように使います。後ろの2つは、文字列を全部スキャンする必要があるので遅いです。最初のは、マッチした時点でスキャンが止まります。

MongoDB は PCRE を正規表現で使っています。 指定できるフラグは:

  • i - 大文字と小文字を区別しない。 大文字、小文字両方にマッチします。
  • m - 複数行。デフォルトでは、 文字列を一行として扱います(たとえ改行が含まれていても)。 "文頭が一致" (^) は、一行の先頭だけがマッチし、"文末が一致" ($) は一行の最後、または最後の改行だけがマッチします。
    m がセットされると、 "文頭" と ”文末” が改行によって区切られまた前後もマッチします。 改行がない場合または、 ^や$を使っていない場合には m は何も意味しません。
  • x - 拡張。 これがセットされた場合、パターンの中の、エスケープされているか、キャラクタークラスの中以外の空白がすべて無視されます。 空白には VTキャラクター(code 11)は含みません。加えて、キャラクタークラスの外側の、エスケープされていない#から改行までも無視されます。
    このオプションは、複雑なパターンの中にコメントを入れることを可能にします。 これは、データ部分の文字列のみに適用されることに注意してください。空白は、パターンの中の特別な文字シーケンスに入れることはできません。例えば, 条件のサブパターンである (?( には空白は入れられません。

配列内の値

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 ] } } } );
$not は、 {$regex: ...} を使った正規表現ではサポートされていません。 $not を使う場合には、全ての正規表現はネイティブなBSONタイプで渡される必要があります(PyMongoでの例: {"$not": re.compile("acme.*corp")} )

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

カーソルメソッド

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);

limit()

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

db.students.find().limit(10).forEach( function(student) { print(student.name + "<p>"); } ); 
シェル(や多くのドライバで)、 limit 0 はlimitを指定しないのと同じことになります。

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を使った場合、使用されません。

sort()

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

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

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

limit() またはインデックスなしでは、ソートがすべてインメモリで行われます。 limit() を使うことで、使用するメモリサイズを減らし、 最適化されたソートアルゴリズムを使うことによりスピードがあがります。

特別なオペレータ

インデックスのキーだけ取得

db.foo.find()._addSpecial("$returnKey" , true )

アイテムをスキャンする数を制限

db.foo.find()._addSpecial( "$maxScan" , 50 )

クエリーをセット

db.foo.find()._addSpecial( "$query" : {x : {$lt : 5}} )
// これと同じ
db.foo.find({x : {$lt : 5}})

結果をソート

db.foo.find()._addSpecial( "$orderby", {x : -1} )
// これと同じ
db.foo.find().sort({x:-1})

結果を返すのではなく、クエリの explain を返す

db.foo.find()._addSpecial( "$explain", true )
// これと同じ
db.foo.find().explain()

スナップショットクエリ

db.foo.find()._addSpecial( "$snapshot", true )
// これと同じ
db.foo.find().snapshot()

インデックスの範囲をセット ( minとmax クエリ指示子 参照)

db.foo.find()._addSpecial("$min" , {x: -20})._addSpecial("$max" , { x : 200 })

結果のディスク上の場所を表示

db.foo.find()._addSpecial("$showDiskLoc" , true)

指定したインデックスを強制

db.foo.find()._addSpecial("$hint", {_id : 1})

group()

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

その他


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