MongoDBでゆるふわDB体験

第3回MongoDBのクエリを使いこなそう

はじめに

本記事では、MongoDBのクエリを解説します。MongoDBはリレーショナルデータベース(以下"RDB"と略記)ではないため、SQLは使用できません。その代わり、MongoDB特有の「Mongoクエリ言語」を用います。Mongoクエリ言語のCRUD操作については公式ドキュメントに詳しい解説があります。

本記事の構成は、最初にMongoクエリ言語の特徴について解説し、2ページ目ではSQLとMongoクエリ言語の比較を行います。3ページ目では、MongoDBクエリ言語の使い方を説明し、最後に、プログラミング言語からの利用の仕方の説明として、Rubyからの利用を説明します。

Mongoクエリ言語の特徴

Mongoクエリ言語には以下の特徴があります。

  • コレクションの各メソッドを用いてCRUD操作をします
  • メソッドの引数にはJSON形式のデータを渡します
  • 変数が使えます
  • 制御構造が使えます
  • カーソルが使えます
  • ドキュメントの要素に簡単にアクセスができます

Mongoクエリ言語はMongoDBのコマンドラインインターフェースであるMongoDBシェルから使用できます。シェルは以下のコマンドから起動します。

$ mongo
MongoDB shell version: 2.2.1
connecting to: test
>

コレクションの各メソッドを用いてCRUD操作をします

たとえば、データを挿入する場合は、コレクション「col1」のメソッドinsertを呼び出します。

> db.col1.insert( { "name" : "mongo" } )

更新、参照、削除といったデータ操作も、すべてコレクションのメソッドを用います。

メソッドの引数にはJSON形式のデータを渡します

データを挿入する場合には、insertの引数にJSONのデータを渡します。

> db.col1.insert( { "string" : "hello" , "array" : [ "sun", "mon", "tue" ] } )

参照する場合は、絞込みの条件をJSON形式で指定します。以下の例では、キー"name"の値が正規表現"/mongo/"に一致するものを検索しています。

> db.col1.find( { "name" => /mongo/ } )

変数が使えます

MongoDBのシェルではJavaScriptの文法で、変数が使えます。そのため、挿入するデータや検索条件をあらかじめ変数で定義しておき、メソッドに渡すことができます。

> data = { "string" : "hello" , "array" : [ "sun", "mon", "tue" ] }
> db.col1.insert( data )

> condition = { "name" => /mongo/ }
> db.col1.find( condition )

制御構造が使えます

MongoDBのシェルではJavaScriptの制御構造が使えます。たとえば、以下のようにforループでデータを挿入できます。

> for (var i = 1; i <= 20; i++) db.col1.insert( { x : 4 , j : i } )

カーソルが使えます

検索結果に対するカーソルを定義して、while等の制御構造でアクセスできます。

> var c = db.col1.find()
> while ( c.hasNext() ) printjson( c.next() )

ドキュメントの要素に簡単にアクセスができます

たとえば以下のようなドキュメントを挿入したとします。

> db.col1.insert( { "key1" : "hello" , "array1" : [ "sun", "mon", "tue" ] } )

すると、そのドキュメントに対して、JavaScriptの文法を用いて、以下のように簡単にアクセスできます。

> doc=db.col1.findOne()  // <- ドキュメントを変数に格納
> printjson(doc["key1"]) // <- キー"key1"の値を表示
"hello"
> printjson(doc["array1"][2]) // <- キーarrayの配列の2番目の要素を表示
"tue"

MongoDBのデータ構造

MongoDBでは、データベースごとに複数のコレクションを持ち、コレクションごとに複数のドキュメントを持ちます。ドキュメントはJSON形式で、以下のような構造をしています。

図1 ドキュメントの例
図1 ドキュメントの例

RDBとMondoDBのデータ構造の比較

MongoDBのデータ構造とRDBのデータ構造の比較を以下の表に記載します。

RDBでの呼称MongoDBでの呼称
databasedatabase
tablecollection
rowdocument
columnfield
indexindex
primary key_id field

※ MongoDBでは、"_id"の値に自動的に一意な文字列が採番されます。

RDBとMongoDBの大きな違いは、RDBではテーブル中のすべてのレコードが同じカラムを有するのに対し、MongoDBではドキュメントごとに自由なフィールドを定義できる点です。

しかし、それ以外のデータ構造は、呼称は異なるものの、RDBとMongoDBで対応するものが存在します。すなわち、RDBにおいて、データベースが複数のテーブルを持ち、テーブルが複数のレコードを持ち、レコードがカラムにより区切られているように、MongoDBにおいても似たような構造を持つことができるのです。

この特徴を生かして、次のページでは、慣れ親しんだSQLとMongoクエリ言語の比較していくことで、 Mongoクエリ言語への理解を深めていきましょう。

MySQLと比較したクエリ

それでは、公式ドキュメントのSQL to MongoDB Mapping Chartを参考に、MongoクエリをMySQLのSQLクエリと比較しながら、Mongoクエリ言語について学びましょう。

以下に、対応表を示します。MongoクエリとSQLクエリで対応する部分は同じ色で表現しています。対応表では、データベース名には"testdb"、テーブル/コレクション名には"products"を使います。

データベース操作

MySQLMongoDB
> SHOW DATABASES;> show dbs
> USE testdb;> use testdb
> CREATE DATABASE testdb;useコマンドで自動生成
> DROP DATABASE testdb;> use testdb
> db.dropDatabase()
> DESC testdb;なし

[参考]

useコマンドでデータベースを選択するだけでは、データベースは永続化されません。 コレクションへ最初のドキュメントを挿入した時点で、データベースは初めて永続化されます。

コレクション操作

MongoDBのコレクションは、MySQLのテーブルに該当します。

MySQLMongoDB
> CREATE TABLE products (...);自動生成 または
> db.createCollection("products")
> ALTER TABLE products ADD ...;自動生成
> SHOW TABLES;> show collections
> DROP TABLE products;> db.products.drop()
> TRUNCATE TABLE products;> db.products.remove()
drop()とremove()の違い

remove()はコレクションが残ります。drop()はコレクションごと削除します。
show collectionsで確認できます。

> db.products.remove() //コレクションの中のすべてのオブジェクトを削除します  
> show collections //確認、productsはまだある
> db.products.drop() //コレクションを削除します
> show collections //確認、productsはない

[参考]

コレクションは、最初のドキュメントを挿入した時点で永続化されます。

ドキュメント操作

MongoDBのドキュメントは、MySQLのレコードに該当します。

選択

MySQLMongoDB
> SELECT * FROM products;> db.products.find()
> SELECT name FROM products WHERE category='A' AND stock ORDER BY name;> db.products.find({ category : 'A' , stock : { $lte : 10 } }, { name : 1 }).sort({ name : 1 })
> SELECT COUNT(*) FROM products;> db.products.count()
> SELECT COUNT(*) FROM products WHERE name LIKE "%camera%" OR category='C';> db.products.find({ $or : [{ name : /camera/ },{ category : 'C' }] }).count()
> SELECT COUNT(stock) FROM products;> db.products.find({ stock : { $exists : true } }).count()
> SELECT * FROM products LIMIT 1;> db.products.findOne()
> SELECT * FROM products LIMIT 5;> db.products.limit(5)
"has more"と表示されたら

MongoDBでは、多くのドキュメントが返された場合、"has more"と表示されます。続きのドキュメントを表示したい場合は、以下のようにします。

> it

一度にすべてのドキュメントを表示したい場合は、以下のようにします。

> db.products.find().toArray()
または
> db.products.find().toArray().forEach(printjsononeline) 

なお、一度に表示できるドキュメントの数を変更したい場合は、次のようにします。

> DBQuery.shellBatchSize = 100

挿入

MySQLMongoDB
> INSERT INTO products VALUES('A',"camera case",5);> db.products.insert({ category : 'A' , name : "camera case" , stock : 5 })

更新

MySQLMongoDB
> UPDATE products SET stock=10 WHERE category='A';> db.products.update({ category : 'A' },{ $set : { stock : 10 } }, false, true)
> UPDATE products SET stock=stock+10 WHERE category='A';> db.products.update({ category : 'A' },{ $inc : { stock : 10 } }, false, true)
updateの引数
update(condition, operation, upsert, multi)

upsert:trueのとき、conditionに一致するデータが無い場合は、新たにデータが登録されます。
multi :trueのとき、conditionに一致したすべてのデータを書き換えます。

削除

MySQLMongoDB
> DELETE FROM products WHERE name="camera case";> db.products.remove({ name : "camera case" })

以上のように、Mongoクエリ言語は、JOINを除くほとんどすべてのSQLクエリを再現することができます。

次のページでは、MongoDBクエリ言語の使い方を学ぶために、一連の利用シーンを想定して、複数のMongoクエリを実行してみます。

Mongoクエリ言語を使ってみよう

それでは、一連の利用シーンを想定して、複数のMongoクエリを実行してみましょう。

MongoDBの実行環境がローカルに無い場合でも、www.mongodb.org から「TRY IT OUT」をクリックしてみてください。ブラウザ上からMongoクエリを簡単に実行できます(ただし、データベースの選択やAggregation Frameworkなど、一部利用できない機能もあります⁠⁠。

想定する利用シーン

今回は、ある学校での利用を想定します。国語、数学、英語の先生が、期末テストの採点結果をそれぞれ入力します。すべての科目の入力が終わった後、最後に、科目ごとの平均点、最高点、最低点と、学生ごとの平均点を算出します。

テスト結果の入力(国語)

はじめに、国語の先生が以下のドキュメントを入力します。

name(名前)subject(科目)score(点数)
fujisakiJapanese80
watanabeJapanese70
hayashidaJapanese60

今回利用するデータベース名は、"school_exam"とします。また、コレクション名は"scores"とします。

データベース"school_exam"を選択し、各ドキュメントを入力します。

> use school_exam
switched to db school_exam
> db.scores.insert({ name: "fujisaki",  subject: "Japanese", score: 80  })
> db.scores.insert({ name: "watanabe",  subject: "Japanese", score: 70  })
> db.scores.insert({ name: "hayashida", subject: "Japanese", score: 60  })
>

入力結果を確認します。

> db.scores.find()
{ "_id": ObjectId("50bf552cb085f3c09c23da5c"), "name": "fujisaki",  "subject": "Japanese", "score": 80  }
{ "_id": ObjectId("50bf552cb085f3c09c23da5d"), "name": "watanabe",  "subject": "Japanese", "score": 70  }
{ "_id": ObjectId("50bf552cb085f3c09c23da5e"), "name": "hayashida", "subject": "Japanese", "score": 60  }
>

入力したドキュメントすべてに自動的に"_id"フィールドが追加され、一意なObjectIdが割り当てられていることがわかります。出力結果をわかりやすくするために、"_id"フィールドを非表示にしてみましょう。

> db.scores.find({},{ "_id": 0 })
{ "name": "fujisaki",  "subject": "Japanese", "score": 80  }
{ "name": "watanabe",  "subject": "Japanese", "score": 70  }
{ "name": "hayashida", "subject": "Japanese", "score": 60  }
>

"_id"以外のフィールドのみ取得することができました。

テスト結果の入力(数学)

次に、数学の先生が入力します。

name(名前)subject(科目)score(点数)
fujisakiMathematics70
watanabeMathematics80
hayashidaMathematics30

3つのドキュメントを入力して、結果を確認します。

> db.scores.insert({ name: "fujisaki",  subject: "Mathematics", score: 70 })
> db.scores.insert({ name: "watanabe",  subject: "Mathematics", score: 80 })
> db.scores.insert({ name: "hayashida", subject: "Mathematics", score: 0 })
>
> db.scores.find({},{ "_id": 0 })
{ "name": "fujisaki",  "subject": "Japanese", "score": 80  }
{ "name": "watanabe",  "subject": "Japanese", "score": 70  }
{ "name": "hayashida", "subject": "Japanese", "score": 60  }
{ "name": "fujisaki",  "subject": "Mathematics", "score": 70 }
{ "name": "watanabe",  "subject": "Mathematics", "score": 80 }
{ "name": "hayashida", "subject": "Mathematics", "score": 0  }
>

"subject"フィールドが"Mathematics"と一致するドキュメントのみ表示します。

> db.scores.find({ "subject": "Mathematics" },{ "_id": 0 })
{ "name": "fujisaki",  "subject": "Mathematics", "score": 70 }
{ "name": "watanabe",  "subject": "Mathematics", "score": 80 }
{ "name": "hayashida", "subject": "Mathematics", "score": 0  }
>

よく見ると、"hayashida"さんの点数を間違って入力していました。正しい点数に修正します。はじめに、ObjectIdを使って修正対象ドキュメントを絞り込む方法でやってみます。

まず、対象ドキュメントのObjectIdを取得します。

> db.scores.find({ "subject": "Mathematics" })
{ "_id": ObjectId("50bf5765b085f3c09c23da6d"), "name": "fujisaki",  "subject": "Mathematics", "score": 70 }
{ "_id": ObjectId("50bf5769b085f3c09c23da6e"), "name": "watanabe",  "subject": "Mathematics", "score": 80 }
{ "_id": ObjectId("50bf576eb085f3c09c23da6f"), "name": "hayashida", "subject": "Mathematics", "score": 0 }
>

対象ドキュメントのObjectIdは、"50bf576eb085f3c09c23da6f"でした。この値を使って、ドキュメントを更新します。

> db.scores.update(
      { "_id": ObjectId("50bf576eb085f3c09c23da6f") },
      { $set : { "score": 30 } }, false, true
  )
>
> db.scores.find({ "subject": "Mathematics" },{ "_id": 0 })
{ "name": "fujisaki",  "subject": "Mathematics", "score": 70 }
{ "name": "watanabe",  "subject": "Mathematics", "score": 80 }
{ "name": "hayashida", "subject": "Mathematics", "score": 30 }
>

正しく更新ができました。

次に、条件により修正対象ドキュメントを絞り込む方法でやってみます。

> db.scores.update(
      { "name": "hayashida", "subject": "Mathematics" },
      { $set  : { "score": 30 } }, false, true
  )
>
> db.scores.find({ "subject": "Mathematics" },{ "_id": 0 })
{ "name": "fujisaki",  "subject": "Mathematics", "score": 70 }
{ "name": "watanabe",  "subject": "Mathematics", "score": 80 }
{ "name": "hayashida", "subject": "Mathematics", "score": 30 }
>

こちらの方法でも、正しく更新ができました。

テスト結果の入力(英語)

最後に入力するはずだった英語の先生は、テストの回答用紙を紛失してしまったようです。ここは運を天に任せて、ランダムで点数を入力することにします。

name(名前)subject(科目)score(点数)
fujisakiEnglish0~100(ランダム)
watanabeEnglish0~100(ランダム)
hayashidaEnglish0~100(ランダム)

第1回 使ってみようMongoDBでも軽く触れましたが、MongoDBはJavaScriptの実行環境を備えています。JavaScriptで1~100のランダムな整数を得る式は、⁠Math.floor(Math.random()*100+1)」です。今回はfor文を使って3つのドキュメントを挿入してみましょう。

> students = [ "fujisaki", "watanabe", "hayashida" ]
> for(var i=0; i

JavaScriptを使って、ドキュメントが挿入できました。

ところで、"hayashida"さんがテストを欠席していたことを思い出しました。該当するドキュメントを削除しましょう。

ObjectIdにより削除する方法もありますが、ここでは条件により削除対象ドキュメントを絞り込む方法でやってみます。

> db.scores.remove({ "name": "hayashida" , "subject": "English" })
>
> db.scores.find({ "subject": "English" },{ "_id": 0 })
{ "name": "fujisaki", "subject": "English", "score": 97 }
{ "name": "watanabe", "subject": "English", "score": 73 }
>

正しく削除できました。

以上で、全科目の入力が終了しました。

集計処理

最後に、科目ごとの平均点、最高点、最低点と、学生ごとの平均点を算出します。

集計処理には、第2回 MongoDB 2.2の新機能でも紹介したAggregation Frameworkを利用します。Aggregation Frameworkについての詳細は、公式ドキュメントのAggregationのページを参照してください。

まずは、科目ごとの平均点を算出します。クエリと実行結果は、以下のようになります。

> db.scores.aggregate(
    { $project: { "subject": 1, "score": 1 } },
    { $group  : { "_id"    : "$subject",
                  "average": { "$avg": "$score" } } }
  )

{ "result": [
    { "_id": "English",     "average": 85 },
    { "_id": "Mathematics", "average": 60 },
    { "_id": "Japanese",    "average": 70 }
  ],
  "ok": 1
}

※"_id"はSQLのGROUP BY句での集計キーに相当します。

次に、科目ごとの最高点を算出します。クエリと実行結果は、以下のようになります。

> db.scores.aggregate(
    { $sort : { "subject": 1, "score": -1 } },
    { $group: { "_id"        : "$subject",
                "top-ranker" : {"$first": "$name" },
                "high-score" : {"$first": "$score" } } }
  )

{ "result": [
    { "_id": "English",     "top-ranker": "fujisaki", "high-score": 97 },
    { "_id": "Mathematics", "top-ranker": "watanabe", "high-score": 80 },
    { "_id": "Japanese",    "top-ranker": "fujisaki", "high-score": 80 }
  ],
  "ok": 1
}

※他に、$maxを利用する方法などもあります。

※$sortのキー"score"の値である"-1"は、降順でのソートを表します。

次に、科目ごとの最低点を算出します。クエリと実行結果は、以下のようになります。

> db.scores.aggregate(
    { $sort : { "subject": 1, "score": -1 } },
    { $group: { "_id"          : "$subject",
                "bottom-ranker": {"$last": "$name" },
                "low-score"    : {"$last": "$score" } } }
  )

{ "result": [
    { "_id": "English",     "bottom-ranker": "watanabe",  "low-score": 73 },
    { "_id": "Mathematics", "bottom-ranker": "hayashida", "low-score": 30 },
    { "_id": "Japanese",    "bottom-ranker": "hayashida", "low-score": 60 }
  ],
  "ok": 1
}

※他に、$minを利用する方法や、最高点算出クエリの$sortのキー"score"の値を1にする方法などもあります。

最後に、学生ごとの平均点を算出します。クエリと実行結果は、以下のようになります。

> db.scores.aggregate(
    { $project: { "name": 1, "score": 1 } },
    { $group  : { "_id"    : "$name",
                  "average": { "$avg": "$score" }
                } }
  )

{ "result": [
    { "_id": "hayashida", "average": 45 },
    { "_id": "watanabe",  "average": 74.33333333333333 },
    { "_id": "fujisaki",  "average": 82.33333333333333 }
  ],
  "ok": 1
}

次のページでは、プログラミング言語からの利用の仕方の説明として、Rubyからの利用を説明します。

RubyからMongoDBを触ってみる

MongoDBではアプリケーションから利用するためのたくさんのドライバが用意されています。公式ドキュメントのDriversのページに一覧があります。今回は、その中の1つであるRubyのドライバを触ってみましょう。

[準備]

以下の環境を前提としています。

  • Ruby 1.9.3-p194
  • MongoDB 2.2.1

MongoDBのRubyドライバのインストール

MongoDBのRubyドライバは、Rubyのパッケージ管理システムであるgemに登録されているため、gemコマンドで簡単にインストールすることができます。

以下のコマンドでRubyドライバをインストールします。

# gem install mongo

また、BSONシリアライズのために、以下のbsonのgemもインストールする必要があります。

# gem install bson

[注意]

version 0.2より前のRubyドライバでは、BSONシリアライズ機能は同梱されているため、bsonのgemのインストールは不要です。

BSONシリアライズの性能を向上させたい場合は、以下のbson_extをインストールするとよいでしょう。C言語で書かれているため、性能が向上します。

# gem install bson_ext

インタラクティブモード(irb)で触ってみる

irbはrubyのインタラクティブモードです。対話的にrubyを実行できます。まずはこれでMongoDBとの接続を試してみましょう。

irbを起動します。

$ irb

MongoDB-Ruby-Driverをロードします。

irb> require 'mongo'
=> true

MongoDBに接続します。

irb> con = Mongo::Connection.new
=> #<Mongo::Connection:0x89422c8 @host_to_try=["localhost", 27017],・・・

データベースを指定して変数に格納します。

irb> db = con.db("school_exam")
=> #<Mongo::DB:0x893f30c @name="school_exam", ・・・

コレクションを指定して変数に格納します。

irb> coll = db["students"]
=> #<Mongo::コレクション:0x8620e64 @name="students", ・・・

コレクションにドキュメントを挿入します。

irb> coll.insert( { "name" => "fujisaki", "age" => 31  } )
=> BSON::ObjectId('50c7732f3e91d8106f000001')
irb> coll.insert( { "name" => "watanabe", "age" => 30  } )
=> BSON::ObjectId('50c773403e91d8106f000002')
irb> coll.insert( { "name" => "hayashida", "age" => 24 } )
=> BSON::ObjectId('50c773453e91d8106f000003')

コレクションの中のドキュメントの数を調べます。

irb> coll.count
=> 3

コレクションの中のドキュメントをRubyの配列に変換します。

irb> coll.find.to_a
=> [{"_id"=>BSON::ObjectId('50c7732f3e91d8106f000001'), "name"=>"fujisaki",  "age"=>31},
    {"_id"=>BSON::ObjectId('50c773403e91d8106f000002'), "name"=>"watanabe",  "age"=>30},
    {"_id"=>BSON::ObjectId('50c773453e91d8106f000003'), "name"=>"hayashida", "age"=>24}]

コレクションの中のドキュメントをループで回します。

irb> coll.find.each { |doc|
irb*    p doc
irb*    p doc["name"]
irb*    p doc["age"]
irb* }
{"_id"=>BSON::ObjectId('50c7732f3e91d8106f000001'), "name"=>"fujisaki", "age"=>31}
"fujisaki"
31
{"_id"=>BSON::ObjectId('50c773403e91d8106f000002'), "name"=>"watanabe", "age"=>30}
"watanabe"
30
{"_id"=>BSON::ObjectId('50c773453e91d8106f000003'), "name"=>"hayashida", "age"=>24}
"hayashida"
24
=> nil

キー"name"に値"wata"を含むドキュメントを正規表現で検索します。

irb> coll.find( { "name" => /wata/ } ).to_a
=> [{"_id"=>BSON::ObjectId('50c773403e91d8106f000002'), "name"=>"watanabe", "age"=>30}]

[注意]

最後にto_aを付けて配列化している理由は、to_aをつけないとカーソルのオブジェクトが返ってきて、中身が見えないためです。

_idを指定して検索します。_idは環境によって変わるため、値を変更してください。以下は筆者の環境で実施した結果です。

irb> coll.find( { "_id"  => BSON::ObjectId('4f7b20b4e4d30b35c9000049') } ).to_a
=> [{"_id"=>BSON::ObjectId('50c7732f3e91d8106f000001'), "name"=>"fujisaki", "age"=>31}]

[注意]

MongoDBの_idは単なる文字列ではないため、_idを格納するBSONオブジェクトを作成して、問い合わせる必要があります。

キーが"age"の値でソートします。

irb> coll.find.sort("age").to_a
=> [{"_id"=>BSON::ObjectId('50c773453e91d8106f000003'), "name"=>"hayashida", "age"=>24},
    {"_id"=>BSON::ObjectId('50c773403e91d8106f000002'), "name"=>"watanabe", "age"=>30},
    {"_id"=>BSON::ObjectId('50c7732f3e91d8106f000001'), "name"=>"fujisaki", "age"=>31}]

キー"name"の値が"fujisaki"であるドキュメントのキー"age"の値を更新します。

irb> coll.update( {"name" => "fujisaki"} , {"$set" => {"age" => "32"} } )
=> 88

※88 という返り値はsocket上で送信されるパケットサイズ(単位はbyte)です。環境によって変わります。詳細は省きますが、気になる人はgithubからドライバのソースを見てみましょう。

mongo-ruby-driver/lib/mongo/networking.rb

キー"name"の値が"fujisaki"であるドキュメントを削除します。

irb> coll.remove("name" => "fujisaki")
=> true

すべてのドキュメントを削除します。

irb> coll.remove()
=> true

Rubyのソースコードを書いてみる

基本的にはirbで実行したコマンドを列挙すればOKです。ソースコードは以下のようになります。

require 'mongo'

con = Mongo::Connection.new #MongoDBに接続
db = con.db("school_exam") #DBを指定
coll = db["students"] #コレクションを指定

#挿入
coll.insert( { "name" => "fujisaki", "age" => 31 } )
coll.insert( { "name" => "watanabe", "age" => 30 } )
coll.insert( { "name" => "hayashida", "age" => 24 } )

#コレクションの中のドキュメントの数
p coll.count

#コレクションの中のドキュメントをRubyの配列に変換
p coll.find().to_a

#コレクションの中のドキュメントをループで回す
coll.find.each { |doc|
  p doc
  p doc["name"]
  p doc["age"]
}

#キー"name"に値"wata"を含むドキュメントを正規表現で検索
p coll.find( { "name" => /wata/ } ).to_a

#IDを指定して参照
#_idは環境によって変わるためここではコメントアウトします
#p coll.find( { "_id"  => BSON::ObjectId('xxxx') } ).to_a

#キーが"age"の値でソート
p coll.find.sort("age").to_a

#キー"name"の値が"fujisaki"であるドキュメントのキー"age"の値を更新
coll.update( {"name" => "fujisaki"} , {"$set" => {"age" => "32"} } )

#キー"name"の値が"fujisaki"であるドキュメントの削除
coll.remove("name" => "fujisaki")

#すべて削除
#MongoDB shellから確認するため、コメントアウトします
#coll.remove()

このソースコードをmongo_sample.rbとして保存してください。実行すると以下のような出力になります。

$ ruby mongo_sample.rb
3
[{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000001'), "name"=>"fujisaki", "age"=>31}, {"_id"=>BSON::ObjectId('50c979fdbb050f12bc000002'), "name"=>"watanabe", "age"=>30}, {"_id"=>BSON::ObjectId('50c979fdbb050f12bc000003'), "name"=>"hayashida", "age"=>24}]
{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000001'), "name"=>"fujisaki", "age"=>31}
"fujisaki"
31
{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000002'), "name"=>"watanabe", "age"=>30}
"watanabe"
30
{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000003'), "name"=>"hayashida", "age"=>24}
"hayashida"
24
[{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000002'), "name"=>"watanabe", "age"=>30}]
[{"_id"=>BSON::ObjectId('50c979fdbb050f12bc000003'), "name"=>"hayashida", "age"=>24}, {"_id"=>BSON::ObjectId('50c979fdbb050f12bc000002'), "name"=>"watanabe", "age"=>30}, {"_id"=>BSON::ObjectId('50c979fdbb050f12bc000001'), "name"=>"fujisaki", "age"=>31}]

シェルを起動させてfindしてみましょう。rubyからinsertできてますか!?

$ mongo 
MongoDB shell version: 2.2.1
connecting to: test
> use school_exam
switched to db school_exam
> db.students.find() //結果はみなさんの環境で確認してみてください

次回のテーマ

今回はMongoDBクエリ言語を説明しました。実際にコマンドを打ってみて、ドキュメントをinsertしfindすることで理解が早くなるかと思います。文中でも紹介しましたが、www.mongodb.org「TRY IT OUT」からOnline Shellが使えますので、まだMongoDBを触ったことがない方はぜひ試してみてください。

次回は、MongoDBのスケールアウトの仕組みであるShardingについて説明します。多くのコマンドを紹介して、実際にSharding環境を構築するまでの手順を記載する予定です。

おすすめ記事

記事・ニュース一覧