はじめに
7つのデータベース 7つの世界の第5章 MongoDBのメモです。
1日目
MongoDBインストール
1日目の宿題
やってみよう
1.
JSONドキュメント{ "hello" : "world" }
の中身を印字してみよう。
> db.yattemiyo.insert({"hello": "world"})
WriteResult({ "nInserted" : 1 })
> print(JSON.stringify(db.yattemiyo.findOne({hello: "world"}, {_id: false})))
{"hello":"world"}
>
2.
大文字小文字を区別しない正規表現を使って、文字列newが含まれる町を選択してみよう。
> db.towns.find({name: /new/i})
{ "_id" : ObjectId("540bd726c265200143a187d6"), "name" : "New York", "population" : 22200000, "last_census" : ISODate("2009-07-31T00:00:00Z"), "famous_for" : [ "statue of liberty", "food" ], "mayor" : { "name" : "Michael Bloomberg", "party" : "I" } }
>
3.
名前にeが含まれていて、foodかbeerで有名な市をすべて検索してみよう。
> db.towns.find({name: /e/, famous_for: {$in: ["food", "beer"]}})
{ "_id" : ObjectId("540bd726c265200143a187d6"), "name" : "New York", "population" : 22200000, "last_census" : ISODate("2009-07-31T00:00:00Z"), "famous_for" : [ "statue of liberty", "food" ], "mayor" : { "name" : "Michael Bloomberg", "party" : "I" } }
>
4.
新しいデータベース「blogger」とコレクション「articles」を作ってみよう。新しい記事に作者の名前・メールアドレス・作成日・本文を挿入してみよう。
> use blogger
switched to db blogger
> db.articles.insert({author: "nownabe", email: "nownabe@hogehoge.com", created_on: ISODate("2014-09-09"), text: "foo\nbar"})
WriteResult({ "nInserted" : 1 })
> db.articles.find()
{ "_id" : ObjectId("540f1cc1128b0ea47aa14735"), "author" : "nownabe", "email" : "nownabe@hogehoge.com", "created_on" : ISODate("2014-09-09T00:00:00Z"), "text" : "foo\nbar" }
>
5.
名前と本文を持つコメントの配列を記事に追加してみよう。
> db.articles.update({_id: ObjectId("540f1cc1128b0ea47aa14735")}, {$set: {comments: [{name: "kani", text: "hyoe"}]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.articles.find()
{ "_id" : ObjectId("540f1cc1128b0ea47aa14735"), "author" : "nownabe", "email" : "nownabe@hogehoge.com", "created_on" : ISODate("2014-09-09T00:00:00Z"), "text" : "foo\nbar", "comments" : [ { "name" : "kani", "text" : "hyoe" } ] }
>
6.
外部のJavascriptファイルにあるクエリを実行してみよう。
$ echo '"count(countries): " + db.countries.count()' > day1-6.js
$ mongo --quiet book < day1-6.js
2日目
2日目の宿題
調べてみよう
1.
adminコマンドのショートカットを探してみよう。
> db.adminCommand
function ( obj ){
if ( this._name == "admin" )
return this.runCommand( obj );
return this.getSiblingDB( "admin" ).runCommand( obj );
}
>
2.
クエリとカーソルのオンラインドキュメントを探してみよう。
3.
MongoDBのmapreduceのドキュメントを探してみよう。
4. JavaScriptのインターフェイスを使って、help()・findOne()・stats()の3つの関数を調査してみよう。
> db.cities.help
> db.cities.findOne
> db.cities.stats
やってみよう
1.
カウントの合計値を出力するfinalize()メソッドを実装してみよう。
※おそらく、code/mongo/reduce_2.js
のようなコードにしなくてもいいように出力のキーをcountからtotalにしろって話
reduce = function(key, values){
var total = 0;
for(var i=0; i<values.length; i++) {
total += values[i].count
}
return {count: total}
}
finalize = function(key, value) {
return {total: value.count}
}
results = db.runCommand({
mapReduce: "phones",
map: map,
reduce: reduce,
out: "phones.report2",
finalize: finalize
})
2.
あなたが選んだ言語のドライバをインストールして、データベースに接続してみよう。コレクションを作って、フィールドにインデックスを作成してみよう。
Rubyでやりました。
http://docs.mongodb.org/ecosystem/drivers/ruby/
require 'mongo'
client = Mongo::MongoClient.new
db = client["book"]
coll = db["shukudai_2_2"]
coll.remove
1.upto(100) do |i|
coll.insert({
_id: i,
created_at: Time.now,
fizzbuzz: [i%3, i%5].include?(0) ? ( (i%3).zero? ? "fizz" : "" ) + ( (i%5).zero? ? "buzz" : "") : i
})
end
気づいたらfizzbuzzになってました。
3日目
3日目の宿題
調べてみよう
1.
レプリカセットの設定オプションについて、オンラインドキュメントで調べてみよう
2.
球体ジオインデックスの作り方を探してみよう
やってみよう
1.
Mongoは、境界となる形(四角形や丸)をサポートしている。ロンドンの中心から50マイル四方の範囲にあるすべての都市を見つけてみよう。
MongoDBのクエリでは四角形の左下と右上の座標を2つ渡す必要があるので、それを計算する。
http://docs.mongodb.org/manual/reference/operator/query/box/
ロンドンのGeoは[51.507778, -0.128056]らしい。
(GeoHackより)
このGeoってのは[Latitude, Longtitude]
([緯度, 経度]
)になってる。
また、1マイル=1.6kmとすると50マイル=80km。
地球は周囲4万キロの真球として計算する。
緯度は簡単に計算できる。
90 / 40000 * 80 = 0.18
なので、ロンドンの南北50マイルのGeoは、[51.327778, -0.128056]
〜[51.687778, -0.128056]
経度はちょっと複雑になる。
経度と距離の関係は、緯度によって変化する。
しかし、ココによると過剰な精度はいらぬと書いてあるので、このページの表を参考にする。
といっても緯度50度の値はないので、だいたい1度70kmぐらいだろうってことにする。
すると、50マイルというのは80 / 70 = 1.1429
度になる。
よって、ロンドンの50マイル四方で南西の座標は[51.327778, -1.270956]
、北東の座標は[51.687778, 1.014844]
となる。
mongos> db.cities.find({location: {$geoWithin: {$box: [[51.327778, -1.270956], [51.687778, 1.014844]]}}})
{ "_id" : ObjectId("541e7dc1051a80368833da31"), "name" : "Holborn", "country" : "GB", "timezone" : "Europe/London", "population" : 22000, "location" : { "latitude" : 51.52124, "longitude" : -0.11347 } }
{ "_id" : ObjectId("541e7dc1051a80368833d486"), "name" : "London", "country" : "GB", "timezone" : "Europe/London", "population" : 7556900,"location" : { "latitude" : 51.50853, "longitude" : -0.12574 } }
{ "_id" : ObjectId("541e7dc1051a80368833d6b0"), "name" : "Farnham Royal", "country" : "GB", "timezone" : "Europe/London", "population" : 6187, "location" : { "latitude" : 51.53333, "longitude" : -0.61667 } }
{ "_id" : ObjectId("541e7dc1051a80368833d310"), "name" : "Potters Bar", "country" : "GB", "timezone" : "Europe/London", "population" : 22192, "location" : { "latitude" : 51.68333, "longitude" : -0.16667 } }
{ "_id" : ObjectId("541e7dc1051a80368833da43"), "name" : "Gerrards Cross", "country" : "GB", "timezone" : "Europe/London", "population" : 7342, "location" : { "latitude" : 51.5895, "longitude" : -0.55043 } }
{ "_id" : ObjectId("541e7dc1051a80368833d2f4"), "name" : "Radlett", "country" : "GB", "timezone" : "Europe/London", "population" : 8213, "location" : { "latitude" : 51.68333, "longitude" : -0.31667 } }
{ "_id" : ObjectId("541e7dc1051a80368833d943"), "name" : "Beaconsfield", "country" : "GB", "timezone" : "Europe/London", "population" : 12566, "location" : { "latitude" : 51.6, "longitude" : -0.63333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d0cc"), "name" : "Windlesham", "country" : "GB", "timezone" : "Europe/London", "population" : 4194, "location" : { "latitude" : 51.36667, "longitude" : -0.65 } }
{ "_id" : ObjectId("541e7dc1051a80368833d9c7"), "name" : "Amersham", "country" : "GB", "timezone" : "Europe/London", "population" : 21731, "location" : { "latitude" : 51.66667, "longitude" : -0.61667 } }
{ "_id" : ObjectId("541e7dc1051a80368833d371"), "name" : "Ottershaw", "country" : "GB", "timezone" : "Europe/London", "population" : 3451, "location" : { "latitude" : 51.35, "longitude" : -0.53333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d831"), "name" : "Chalfont Saint Peter", "country" : "GB", "timezone" : "Europe/London", "population" : 20059, "location" : { "latitude" : 51.60885, "longitude" : -0.55618 } }
{ "_id" : ObjectId("541e7dc1051a80368833d37a"), "name" : "Old Windsor", "country" : "GB", "timezone" : "Europe/London", "population" : 7168, "location" : { "latitude" : 51.45, "longitude" : -0.58333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d832"), "name" : "Chalfont Saint Giles", "country" : "GB", "timezone" : "Europe/London", "population" : 4815, "location" : { "latitude" : 51.63184, "longitude" : -0.57026 } }
{ "_id" : ObjectId("541e7dc1051a80368833d0cb"), "name" : "Windsor", "country" : "GB", "timezone" : "Europe/London", "population" : 28324, "location" : { "latitude" : 51.48333, "longitude" : -0.6 } }
{ "_id" : ObjectId("541e7dc1051a80368833da53"), "name" : "Amersham on the Hill", "country" : "GB", "timezone" : "Europe/London", "population" : 17719, "location" : { "latitude" : 51.67468, "longitude" : -0.60742 } }
{ "_id" : ObjectId("541e7dc1051a80368833d228"), "name" : "Slough", "country" : "GB", "timezone" : "Europe/London", "population" : 134072, "location" : { "latitude" : 51.5, "longitude" : -0.58333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d75a"), "name" : "Denham", "country" : "GB", "timezone" : "Europe/London", "population" : 6548, "location" : { "latitude" : 51.56667, "longitude" : -0.5 } }
{ "_id" : ObjectId("541e7dc1051a80368833d250"), "name" : "Shepperton", "country" : "GB", "timezone" : "Europe/London", "population" : 10106, "location" : { "latitude" : 51.38333, "longitude" : -0.43333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d601"), "name" : "Harefield", "country" : "GB", "timezone" : "Europe/London", "population" : 6683, "location" : { "latitude" : 51.6, "longitude" : -0.48333 } }
{ "_id" : ObjectId("541e7dc1051a80368833d1bf"), "name" : "Sunbury", "country" : "GB", "timezone" : "Europe/London", "population" : 27784, "location" : { "latitude" : 51.4, "longitude" : -0.4 } }
Type "it" for more
mongos>
2.
6つのサーバーを起動してみよう。2つのレプリカセットに3つのサーバーがあり、レプリカセットはいずれもシャードである。設定サーバーとmongosを起動してみよう。それらに対して、GridFSを実行してみよう。
$ mkdir data
$ cd data
$ mkdir mongod1{a,b,c} mongod2{a,b,c} mongo{c,s}
$ mongod --shardsvr --replSet rs1 --dbpath ./mongod1a --port 27011 --noprealloc --smallfiles --nojournal
$ mongod --shardsvr --replSet rs1 --dbpath ./mongod1b --port 27012 --noprealloc --smallfiles --nojournal
$ mongod --shardsvr --replSet rs1 --dbpath ./mongod1c --port 27013 --noprealloc --smallfiles --nojournal
$ mongod --shardsvr --replSet rs2 --dbpath ./mongod2a --port 27021 --noprealloc --smallfiles --nojournal
$ mongod --shardsvr --replSet rs2 --dbpath ./mongod2b --port 27022 --noprealloc --smallfiles --nojournal
$ mongod --shardsvr --replSet rs2 --dbpath ./mongod2c --port 27023 --noprealloc --smallfiles --nojournal
$ mongod --configsvr --dbpath ./mongoc --port 27018 --nojournal
$ mongos --configdb localhost:27018 --chunkSize 1 --port 27017
$ mongo localhost:27011
> rs.initiate({_id: "rs1", members: [
... {_id: 1, host: "localhost:27011"},
... {_id: 2, host: "localhost:27012"},
... {_id: 3, host: "localhost:27013"}
... ]})
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
> exit
bye
$ mongo localhost:27021
> rs.initiate({_id: "rs2", members: [
... {_id: 1, host: "localhost:27021"},
... {_id: 2, host: "localhost:27022"},
... {_id: 3, host: "localhost:27023"}
... ]})
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
> exit
bye
$ mongo admin
mongos> sh.addShard("rs1/localhost:27011,localhost:27012,localhost:27013")
{ "shardAdded" : "rs1", "ok" : 1 }
mongos> sh.addShard("rs2/localhost:27021,localhost:27022,localhost:27023")
{ "shardAdded" : "rs2", "ok" : 1 }
mongos> sh.enableSharding("test")
{ "ok" : 1 }
mongos> sh.shardCollection("test.cities", {name: 1})
{ "collectionsharded" : "test.cities", "ok" : 1 }
mongos> exit
bye
$ cd ~/code/mongo
$ mongoimport --db test --collection cities --type json mongo_cities1000.json
$ mongo
MongoDB shell version: 2.6.4
connecting to: test
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 4,
"minCompatibleVersion" : 4,
"currentVersion" : 5,
"clusterId" : ObjectId("541e9966c4aeff3a3ef20a54")
}
shards:
{ "_id" : "rs1", "host" : "rs1/localhost:27011,localhost:27012,localhost:27013" }
{ "_id" : "rs2", "host" : "rs2/localhost:27021,localhost:27022,localhost:27023" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : true, "primary" : "rs1" }
test.cities
shard key: { "name" : 1 }
chunks:
rs2 8
rs1 17
too many chunks to print, use verbose if you want to force print
mongos> exit
bye
$ mongofiles put distinct_digits.js
connected to: 127.0.0.1
added file: { _id: ObjectId('541ea0bc7926af426fbf6bfa'), filename: "distinct_digits.js", chunkSize: 261120, uploadDate: new Date(1411293372268), md5: "b2ff3a355d0c6532933c60fe2a0d0592", length: 767 }
done!
$ mongofiles list
connected to: 127.0.0.1
distinct_digits.js 767