MongoDBのGetting Startedを試してみる

http://docs.mongodb.org/manual/tutorial/getting-started/
いわずとしれたNoSQLなDB、MongoDBのGetting Startedを試していきます。環境はCloud9です。
感想：Getting Startedにしても内容が薄いかなと思いました。こっちのほうが面白かった？([MongoDB CRUD Tutorials](http://docs.mongodb.org/manual/applications/crud/))

#Getting Started with MongoDB
##start db server
Getting StartedではDBのインストールは完了してることになっています。Cloud9ではプレインストールされているので、そちらを使っていきます。
https://docs.c9.io/v1.0/docs/setting-up-mongodb
1)データストア場所としてdataディレクトリを作成
2)起動シェルを作成
3)実行

```
$ mkdir data
$ echo 'mongod --bind_ip=$IP --dbpath=data --nojournal --rest "$@"' > mongod
$ chmod a+x mongod
$ ./mongod
```
簡単ですね。--nojournalオプションがないと２GBほど容量を事前に確保するそうです。

##Connect to a Database
###Connect to a mongod
接続にはmongoコマンドをつかうそうです。Cloud9にもプリインストールされていることでしょう。使ってみます。

```
$ mongo
MongoDB shell version: 2.6.5
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user
Server has startup warnings: 
2015-04-06T06:36:53.756+0000 ** WARNING: --rest is specified without --httpinterface,
2015-04-06T06:36:53.756+0000 **          enabling http interface
> 
```
なにかWARNINGが出ていますが繋がりましたね。
--restオプションを付けて起動する場合は--httpinterfaceオプションを明示的につけろといった内容でしょう。--restはREST APIを提供するためのオプションのようです。とりあえず不要なので、起動バッチから--restを削除し、サーバを再起動、再接続してみます。

```
$ mongo
MongoDB shell version: 2.6.5
connecting to: test
> 
```
WARNINGは消えましたね。いろいろ他のメッセージも消えてますが、初回のみ表示されるメッセージだったようです。
なお、このプロンプトではjavascriptが実行可能です。

###Select a Database
さて、上の実行結果にもあるように現在testという名前のDBに接続しています。これをdbコマンドで確認しましょう。

```
> db
test
> 
```

できましたね。続いて他にどのようなDBがあるかshow dbsコマンドで確認しましょう。

```
>show dbs
admin  (empty)
local  0.078GB
> 
```
testがありません。どうもtestはこの段階では存在せず、この状態のままinsertなどを実行すると、MongoDBが気を利かせて作成してくれるそうです。
ここではGetting Startedに従いmydbをuseコマンドで作成、使用していきます。

```
> use mydb
switched to db mydb
>
```

できましたね。ここで気になったので再度show dbs、dbコマンドを実行してみました。

```
> show dbs
admin  (empty)
local  0.078GB
test   (empty)
> db
mydb
> 
```
さきほどなかったtestが作成されています。また作ったはずのmydbはリストにありません。おそらくdbをtestに切り替えれば作成されるのでしょう。あまり意味はありませんがやってみます。

```
> use test
switched to db test
> show dbs
admin  (empty)
local  0.078GB
test   (empty)
>
```
作られていませんでした。原文のほうに次のように書いてありました。「データをインサートするまでデータベースを作成しません」。じゃあなぜtestは作成されたのか不可解極まりないですが重要ではないので置いておきます。たぶん特別な存在なのでしょう。use mydbでdbを戻し進めていきましょう。

##Display mongo Help
helpコマンドでヘルプが見れます。またjavascriptでアクセスする際、.help()メソッドでヘルプが得られるそうです。

```
> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
        rs.help()                    replica set helpers
        help admin                   administrative help
        help connect                 connecting to a db help
        help keys                    key shortcuts
        help misc                    misc things to know
        help mr                      mapreduce

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time >= 1ms
        show logs                    show the accessible logger names
        show log [name]              prints out the last segment of log in memory, 'global' is default
        use <db_name>                set current database
        db.foo.find()                list objects in collection foo
        db.foo.find( { a : 1 } )     list objects in foo where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell
> 
```

##Create a Collection and Insert Documents
mydbにコレクションtestDataを作成し、その中にドキュメントをインサートしていきます。コレクションはRelational DBでいうところのテーブルに、ドキュメントはレコードに相当するものでしょう。[対応表](http://docs.mongodb.org/manual/reference/sql-comparison/)がありました。

MongoDBではコレクションはドキュメント挿入時に暗黙的に作られるそうです。よってcreate tableに相当する操作が必要ありません。さらにいえばスキーム定義も不要です。ドキュメント挿入時に動的に解決されるそうです。

ではドキュメントを挿入していきます。まずドキュメントの作成です。ここではnameフィールドをもつｊとｘフィールドをもつｋを作成します。

```
> j = { name : "mongo" }
{ "name" : "mongo" }
> k = { x : 3 }
{ "x" : 3 }
>
```

つぎに作成したドキュメントをコレクションdataTableに挿入します。

```
> db.testData.insert( j )
WriteResult({ "nInserted" : 1 })
> db.testData.insert( k )
WriteResult({ "nInserted" : 1 })
>
```

この段階でようやくmydbとtestDataが作成されます。
確認してみましょう。コレクションの確認はshow collectionsコマンドで行います。これは現在のdbのコレクションを返します。

```
> show dbs
admin  (empty)
local  0.078GB
mydb   0.078GB
test   (empty)
> show collections
system.indexes
testData
>
```

ではtestDataの中身を見てみましょう。findコマンドを使います。

```
> db.testData.find()
{ "_id" : ObjectId("5522372a789c0727a427864e"), "name" : "mongo" }
{ "_id" : ObjectId("55223732789c0727a427864f"), "x" : 3 }
> 
```
格納されてますね。ここでObjectIdが追加されています。全てのMongoDBのドキュメントはユニークな_idフィールドをもっています。
当然のように異なるフィールドをもつドキュメントを挿入していますが、特にそれについての説明はありませんでした。

##Insert Documents using a For Loop or a JavaScript Function
以降の内容を実行するにあたりテストデータを作成しろとのことです。以下ではforループでドキュメントを追加し、結果を確認しています。`WriteResult({ "nInserted" : 1 })`が１回しかでないのに違和感を感じますが、ドキュメントの登録はできているようです。なおfindは途中までしか表示してくれません。続きを見たい場合はさらにitを実行してください。

```
> for (var i = 1; i <= 25; i++) {
... 
...    db.testData.insert( { x : i } )
... 
... }
WriteResult({ "nInserted" : 1 })
> db.testData.find()
{ "_id" : ObjectId("5522372a789c0727a427864e"), "name" : "mongo" }
{ "_id" : ObjectId("55223732789c0727a427864f"), "x" : 3 }
{ "_id" : ObjectId("55223d20789c0727a4278650"), "x" : 1 }
{ "_id" : ObjectId("55223d20789c0727a4278651"), "x" : 2 }
{ "_id" : ObjectId("55223d20789c0727a4278652"), "x" : 3 }
{ "_id" : ObjectId("55223d20789c0727a4278653"), "x" : 4 }
{ "_id" : ObjectId("55223d20789c0727a4278654"), "x" : 5 }
{ "_id" : ObjectId("55223d20789c0727a4278655"), "x" : 6 }
{ "_id" : ObjectId("55223d20789c0727a4278656"), "x" : 7 }
{ "_id" : ObjectId("55223d20789c0727a4278657"), "x" : 8 }
{ "_id" : ObjectId("55223d20789c0727a4278658"), "x" : 9 }
{ "_id" : ObjectId("55223d20789c0727a4278659"), "x" : 10 }
{ "_id" : ObjectId("55223d20789c0727a427865a"), "x" : 11 }
{ "_id" : ObjectId("55223d20789c0727a427865b"), "x" : 12 }
{ "_id" : ObjectId("55223d20789c0727a427865c"), "x" : 13 }
{ "_id" : ObjectId("55223d20789c0727a427865d"), "x" : 14 }
{ "_id" : ObjectId("55223d20789c0727a427865e"), "x" : 15 }
{ "_id" : ObjectId("55223d20789c0727a427865f"), "x" : 16 }
{ "_id" : ObjectId("55223d20789c0727a4278660"), "x" : 17 }
{ "_id" : ObjectId("55223d20789c0727a4278661"), "x" : 18 }
Type "it" for more
> it
{ "_id" : ObjectId("55223d20789c0727a4278662"), "x" : 19 }
{ "_id" : ObjectId("55223d20789c0727a4278663"), "x" : 20 }
{ "_id" : ObjectId("55223d20789c0727a4278664"), "x" : 21 }
{ "_id" : ObjectId("55223d20789c0727a4278665"), "x" : 22 }
{ "_id" : ObjectId("55223d20789c0727a4278666"), "x" : 23 }
{ "_id" : ObjectId("55223d20789c0727a4278667"), "x" : 24 }
{ "_id" : ObjectId("55223d20789c0727a4278668"), "x" : 25 }
>
```

データの準備が整ったので続けていきます。

###Iterate over the Cursor with a Loop
さっきの途中まで表示に関わってきますが、find()はカーソル・イテレーターを返しています。
つまりitを使わずに全行を表示したければ、つぎのようになります。

```
> var c = db.testData.find()
> 
> while ( c.hasNext() ) printjson( c.next() )
{ "_id" : ObjectId("5522372a789c0727a427864e"), "name" : "mongo" }
{ "_id" : ObjectId("55223732789c0727a427864f"), "x" : 3 }
{ "_id" : ObjectId("55223d20789c0727a4278650"), "x" : 1 }
{ "_id" : ObjectId("55223d20789c0727a4278651"), "x" : 2 }
{ "_id" : ObjectId("55223d20789c0727a4278652"), "x" : 3 }
{ "_id" : ObjectId("55223d20789c0727a4278653"), "x" : 4 }
{ "_id" : ObjectId("55223d20789c0727a4278654"), "x" : 5 }
{ "_id" : ObjectId("55223d20789c0727a4278655"), "x" : 6 }
{ "_id" : ObjectId("55223d20789c0727a4278656"), "x" : 7 }
{ "_id" : ObjectId("55223d20789c0727a4278657"), "x" : 8 }
{ "_id" : ObjectId("55223d20789c0727a4278658"), "x" : 9 }
{ "_id" : ObjectId("55223d20789c0727a4278659"), "x" : 10 }
{ "_id" : ObjectId("55223d20789c0727a427865a"), "x" : 11 }
{ "_id" : ObjectId("55223d20789c0727a427865b"), "x" : 12 }
{ "_id" : ObjectId("55223d20789c0727a427865c"), "x" : 13 }
{ "_id" : ObjectId("55223d20789c0727a427865d"), "x" : 14 }
{ "_id" : ObjectId("55223d20789c0727a427865e"), "x" : 15 }
{ "_id" : ObjectId("55223d20789c0727a427865f"), "x" : 16 }
{ "_id" : ObjectId("55223d20789c0727a4278660"), "x" : 17 }
{ "_id" : ObjectId("55223d20789c0727a4278661"), "x" : 18 }
{ "_id" : ObjectId("55223d20789c0727a4278662"), "x" : 19 }
{ "_id" : ObjectId("55223d20789c0727a4278663"), "x" : 20 }
{ "_id" : ObjectId("55223d20789c0727a4278664"), "x" : 21 }
{ "_id" : ObjectId("55223d20789c0727a4278665"), "x" : 22 }
{ "_id" : ObjectId("55223d20789c0727a4278666"), "x" : 23 }
{ "_id" : ObjectId("55223d20789c0727a4278667"), "x" : 24 }
{ "_id" : ObjectId("55223d20789c0727a4278668"), "x" : 25 }
> 
```

##Use Array Operations with the Cursor
さらにカーソルは配列的アクセスを提供しています。

```
> var c = db.testData.find()
> printjson( c [ 4 ] )
{ "_id" : ObjectId("55223d20789c0727a4278652"), "x" : 3 }
> 
```

注意点として、配列的アクセスをする場合、全ドキュメントがRAM上にロードされます。メモリ不足に気を付けてください。

##Query for Specific Documents
findOneはfindと同じパラメータを扱えますが、
戻り値がカーソルではなくドキュメントです。

```
> db.testData.findOne()
{ "_id" : ObjectId("5522372a789c0727a427864e"), "name" : "mongo" }
> 
```

##Limit the Number of Documents in the Result Set
取得数を限定するなら次のようにします。

```
> db.testData.find().limit(3)
{ "_id" : ObjectId("5522372a789c0727a427864e"), "name" : "mongo" }
{ "_id" : ObjectId("55223732789c0727a427864f"), "x" : 3 }
{ "_id" : ObjectId("55223d20789c0727a4278650"), "x" : 1 }
> 
```

##Next Steps with MongoDB
以上で終わりになります。
さらに詳しく知りたい方は以下を参照ください。

[MongoDB CRUD Operations](http://docs.mongodb.org/manual/crud/)
[SQL to MongoDB Mapping Chart](http://docs.mongodb.org/manual/reference/sql-comparison/)
[MongoDB Drivers](http://docs.mongodb.org/ecosystem/drivers)

#感想
なんか思ってたのと違いましたね・・・
てっきり検索とかやるもんだと・・・
そっちはこっちのほうで扱ってるみたいなんで今度やりたいと思います。
[MongoDB CRUD Tutorials](http://docs.mongodb.org/manual/applications/crud/)