以下記錄如何以 cli 方式啟動 MongoDB,以及基本的 CRUD operations。
安裝 MongoDB
要在 centos linux 環境安裝 MongoDB,除了用 yum 安裝之外,還可以直接在 網頁 下載 tgz 檔案,以 CentOS 6 為例,選擇作業系統版本 RHEL 6 Linux 64-bit,點擊 DOWNLOAD 後,就可以下載檔案 mongodb-linux-x86_64-rhel62-3.0.7.tgz。
該壓縮檔裡面,只有一個 bin 目錄,裡面是 mongodb 的所有執行檔,我們將裡面的資料解壓縮到 /usr/share/mongodb 裡面。
tar zxvf mongodb-linux-x86_64-rhel62-3.0.7.tgz /usr/share/
cd /usr/share
mv mongodb-linux-x86_64-rhel62-3.0.7 mongodb
cd mongodb
mkdir -p data/db
mkdir -p logs
執行 mongod ,同時指定 db 以及 logfile 路徑,就可以啟動 mongodb。
/usr/share/mongodb/bin/mongod --dbpath=/usr/share/mongodb/data/db -logpath=/usr/share/mongodb/logs/mongodb.log
這是直接將啟動的參數放在 mongod 命令列中,也可以製作一個設定檔 mongodb.conf,並以 -f 指定設定檔就可以了。
/usr/share/mongodb/bin/mongod -f /etc/mongod.conf
如果希望在背景啟動 mongodb,必須加上 --fork 的參數。
[root@server mongodb]# /usr/share/mongodb/bin/mongod -dbpath=/usr/share/mongodb/data/db -logpath=/usr/share/mongodb/logs/mongodb.log --fork
about to fork child process, waiting until server is ready for connections.
forked process: 9544
child process started successfully, parent exiting
[root@server mongodb]# ps aux|grep mongo
root 9544 1.0 1.3 499800 50308 ? Sl 15:36 0:00 /usr/share/mongodb/bin/mongod -dbpath=/usr/share/mongodb/data/db -logpath=/usr/share/mongodb/logs/mongodb.log --fork
root 9556 0.0 0.0 105388 912 pts/0 S+ 15:36 0:00 grep --color mongo
mongod 的參數分為 一般參數、 windows參數、replication 參數、replica set 參數以及隱藏參數。常用的參數如下:
- dbpath
- logpath
- logappend: logfile 以 append 方式附加到檔案後面
- bind_ip
- port
- fork: 以 daemon 方式啟動 mongod
- journal: 開啟記錄檔功能
- syncdelay: 系統同步更新 disk 的時間,預設為 60s
- directoryperdb: 每個 db 儲存在單獨的目錄中,這樣比較容易區分不同的資料庫
- maxConns: 最大的 client 連線數
- repairpath: 執行 repair 的臨時目錄,如果沒有啟用 journal 功能,異常當機重新啟動後,必須執行 repair
如果要停止 mongod,可使用 db.shutdownServer() 指令
# mongo
> use admin;
switched to db admin
> db.shutdownServer();
2015-11-09T17:23:30.415+0800 I NETWORK DBClientCursor::init call() failed
server should be down...
2015-11-09T17:23:30.417+0800 I NETWORK trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2015-11-09T17:23:30.417+0800 W NETWORK Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused
2015-11-09T17:23:30.417+0800 I NETWORK reconnect 127.0.0.1:27017 (127.0.0.1) failed failed couldn't connect to server 127.0.0.1:27017 (127.0.0.1), connection attempt failed
不能用 kill -9 PID 直接將 mongodb process 刪除,這樣可能會導致 mongodb 的資料損壞。只能透過 kill -2 PID 或 kill -15 PID 停止 mongod process。
CRUD
mongo: MongoDB Shell 是 MongoDB 操作及管理的界面,同時也是一個 JavaScript shell 可以執行 js code。
以下幾點是 mongodb 的一些基本使用概念
- mongo 不需要預先建立 collection,在第一次儲存資料時,就會自動建立
- 文件資料可以儲存任何結構的資料,也不需要修改 schema
每一次儲存資料,都會產生一個欄位 _id,該欄位可儲存任何資料類型,未指定時會自動產生,資料類型為 ObjectId,ObjectId 裡面就隱藏了產生這筆資料的時間。
ObjectId: 是 12 bytes BSON 格式,包含以下資訊:
- 4-byte: 表示 Unix epoch 到現在的秒數,也就是 timestamp
- 3-byte: machine identifier
- 2-byte: process id
- 3-byte: counter,啟始值為一個亂數值
儲存
> user1={name:"sun", age: 12};
{ "name" : "sun", "age" : 12 }
> user2={name:"moon", age: 14};
{ "name" : "moon", "age" : 14 }
>
> db.solar.save(user1);
WriteResult({ "nInserted" : 1 })
> db.solar.save(user2);
WriteResult({ "nInserted" : 1 })
>
> db.solar.find();
{ "_id" : ObjectId("56416af4997bc79c93b12e23"), "name" : "sun", "age" : 12 }
{ "_id" : ObjectId("56416af4997bc79c93b12e24"), "name" : "moon", "age" : 14 }
修改
> db.solar.update({name:"moon"},{$set:{age:"16"}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.solar.find();
{ "_id" : ObjectId("56416af4997bc79c93b12e23"), "name" : "sun", "age" : 12 }
{ "_id" : ObjectId("56416af4997bc79c93b12e24"), "name" : "moon", "age" : "16" }
刪除
> db.solar.remove({name:"moon"});
WriteResult({ "nRemoved" : 1 })
> db.solar.find();
{ "_id" : ObjectId("56416af4997bc79c93b12e23"), "name" : "sun", "age" : 12 }
> db.solar.remove({name:"moon"});
WriteResult({ "nRemoved" : 0 })
> db.solar.find();
{ "_id" : ObjectId("56416af4997bc79c93b12e23"), "name" : "sun", "age" : 12 }
_id 欄位可以自訂,但不能重複
> user3={_id:"id_star", name:"star", age: 18};
{ "_id" : "id_star", "name" : "star", "age" : 18 }
> db.solar.save(user3);
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : "id_star" })
>
> user4={_id:"id_star", name:"star2", age: 20};
{ "_id" : "id_star", "name" : "star2", "age" : 20 }
> db.solar.save(user4);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>
> db.solar.find();
{ "_id" : ObjectId("56416af4997bc79c93b12e23"), "name" : "sun", "age" : 12 }
{ "_id" : "id_star", "name" : "star2", "age" : 20 }
> db.solar.insert(user4);
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.solar.$_id_ dup key: { : \"id_star\" }"
}
})
查詢後回傳 cursor,it可取得下一頁資料
> for( var i=1; i<=40; i++ ) db.users.save( {userid:"user_"+i} );
WriteResult({ "nInserted" : 1 })
> db.users.find( );
{ "_id" : ObjectId("5641882a997bc79c93b12e39"), "userid" : "user_1" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3a"), "userid" : "user_2" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3b"), "userid" : "user_3" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3c"), "userid" : "user_4" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3d"), "userid" : "user_5" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3e"), "userid" : "user_6" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3f"), "userid" : "user_7" }
{ "_id" : ObjectId("5641882a997bc79c93b12e40"), "userid" : "user_8" }
{ "_id" : ObjectId("5641882a997bc79c93b12e41"), "userid" : "user_9" }
{ "_id" : ObjectId("5641882a997bc79c93b12e42"), "userid" : "user_10" }
{ "_id" : ObjectId("5641882a997bc79c93b12e43"), "userid" : "user_11" }
{ "_id" : ObjectId("5641882a997bc79c93b12e44"), "userid" : "user_12" }
{ "_id" : ObjectId("5641882a997bc79c93b12e45"), "userid" : "user_13" }
{ "_id" : ObjectId("5641882a997bc79c93b12e46"), "userid" : "user_14" }
{ "_id" : ObjectId("5641882a997bc79c93b12e47"), "userid" : "user_15" }
{ "_id" : ObjectId("5641882a997bc79c93b12e48"), "userid" : "user_16" }
{ "_id" : ObjectId("5641882a997bc79c93b12e49"), "userid" : "user_17" }
{ "_id" : ObjectId("5641882a997bc79c93b12e4a"), "userid" : "user_18" }
{ "_id" : ObjectId("5641882a997bc79c93b12e4b"), "userid" : "user_19" }
{ "_id" : ObjectId("5641882a997bc79c93b12e4c"), "userid" : "user_20" }
Type "it" for more
> it
{ "_id" : ObjectId("5641882a997bc79c93b12e4d"), "userid" : "user_21" }
{ "_id" : ObjectId("5641882a997bc79c93b12e4e"), "userid" : "user_22" }
{ "_id" : ObjectId("5641882a997bc79c93b12e4f"), "userid" : "user_23" }
{ "_id" : ObjectId("5641882a997bc79c93b12e50"), "userid" : "user_24" }
{ "_id" : ObjectId("5641882a997bc79c93b12e51"), "userid" : "user_25" }
{ "_id" : ObjectId("5641882a997bc79c93b12e52"), "userid" : "user_26" }
{ "_id" : ObjectId("5641882a997bc79c93b12e53"), "userid" : "user_27" }
{ "_id" : ObjectId("5641882a997bc79c93b12e54"), "userid" : "user_28" }
{ "_id" : ObjectId("5641882a997bc79c93b12e55"), "userid" : "user_29" }
{ "_id" : ObjectId("5641882a997bc79c93b12e56"), "userid" : "user_30" }
{ "_id" : ObjectId("5641882a997bc79c93b12e57"), "userid" : "user_31" }
{ "_id" : ObjectId("5641882a997bc79c93b12e58"), "userid" : "user_32" }
{ "_id" : ObjectId("5641882a997bc79c93b12e59"), "userid" : "user_33" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5a"), "userid" : "user_34" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5b"), "userid" : "user_35" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5c"), "userid" : "user_36" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5d"), "userid" : "user_37" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5e"), "userid" : "user_38" }
{ "_id" : ObjectId("5641882a997bc79c93b12e5f"), "userid" : "user_39" }
{ "_id" : ObjectId("5641882a997bc79c93b12e60"), "userid" : "user_40" }
可用 while 搭配 cursor.hasNext 進行迴圈處理
> var cursor = db.users.find();
> while ( cursor.hasNext() ) printjson(cursor.next());
{ "_id" : ObjectId("5641882a997bc79c93b12e39"), "userid" : "user_1" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3a"), "userid" : "user_2" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3b"), "userid" : "user_3" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3c"), "userid" : "user_4" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3d"), "userid" : "user_5" }
//..... 省略
也可以用 forEach
> db.users.find().forEach(printjson);
{ "_id" : ObjectId("5641882a997bc79c93b12e39"), "userid" : "user_1" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3a"), "userid" : "user_2" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3b"), "userid" : "user_3" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3c"), "userid" : "user_4" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3d"), "userid" : "user_5" }
也可以把 cursor 當成陣列
> var cursor = db.users.find();
> printjson(cursor[5]);
{ "_id" : ObjectId("5641882a997bc79c93b12e3e"), "userid" : "user_6" }
> while ( cursor.hasNext() ) printjson(cursor.next());
> printjson(cursor[6]);
{ "_id" : ObjectId("5641882a997bc79c93b12e3f"), "userid" : "user_7" }
_id 裡面就隱藏了資料建立時間
> db.users.find().forEach(function (doc){ d = doc._id.getTimestamp(); print(d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()) })
2015-11-10 14:1:14
2015-11-10 14:1:14
2015-11-10 14:1:14
2015-11-10 14:1:14
//.... 省略
條件查詢
> db.users.find({userid:"user_10"}).forEach(printjson);
{ "_id" : ObjectId("5641882a997bc79c93b12e42"), "userid" : "user_10" }
自訂回傳欄位的條件查詢
> db.users.find({userid:"user_10"},{_id:true}).forEach(printjson);
{ "_id" : ObjectId("5641882a997bc79c93b12e42") }
findOne: 只取得第一筆資料
> printjson(db.users.findOne({userid:"user_10"}));
{ "_id" : ObjectId("5641882a997bc79c93b12e42"), "userid" : "user_10" }
limit: 限制回傳資料的筆數
> db.users.find().limit(3);
{ "_id" : ObjectId("5641882a997bc79c93b12e39"), "userid" : "user_1" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3a"), "userid" : "user_2" }
{ "_id" : ObjectId("5641882a997bc79c93b12e3b"), "userid" : "user_3" }
進階查詢
首先準備測試資料
> db.mate.save({userid:"john", username:"John Lin", city:"Taipei", age: 20, room:"301"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"muder", username:"Muder Yen", city:"Taichung", age: 19, room:"301"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"mary", username:"Mary Wang", city:"Tainan", age: 23, room:"601"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"celina", username:"Celina Lin", city:"Taichung", age: 20, room:"601"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"lunar", username:"Lunar Wang", city:"I Lan", age: 22, room:"302"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"danny", username:"Danny Huang", city:"Taipei"});
WriteResult({ "nInserted" : 1 })
> db.mate.save({userid:"johnny", username:"Johnny Lo", city:"Taipei", age: null});
WriteResult({ "nInserted" : 1 })
> db.mate.find();
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
$gt 超過 22 歲的人
> db.mate.find( {age:{ $gt: 22}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
$gte 大於等於 22 歲
> db.mate.find( {age:{ $gte: 22}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
$ne: 不等於 22
> db.mate.find( {age:{ $ne: 22}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
$mod: 除以10餘0
> db.mate.find( {age:{ $mod: [10,0]}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
$all: 完全等於 20
> db.mate.find( {age:{ $all:[20]}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
$in: 22 或 23 歲
> db.mate.find( {age:{ $in:[22, 23]}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
$nin: 不等於 22 或 23
> db.mate.find( {age:{ $nin:[22, 23]}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
$exists: 不存在 age 欄位
> db.mate.find( {age:{$exists:false}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
null: age 欄位為 null,不存在 age 也包含在內
> db.mate.find( {age:null} );
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
有 age 欄位且 age 為 null
> db.mate.find( {age:{$in:[null], $exists:true}} );
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
$regex: username 以 M 為開頭
> db.mate.find( {username:{ $regex:/^M.*/ }} );
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
$not: username 不以 M 為開頭
> db.mate.find( {username:{ $not:/^M.*/ }} );
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
以 javascript function 進行搜尋
> f=function() {return this.age>22;}
function () {return this.age>22;}
> db.mate.find(f);
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
count(): 計算資料筆數
> db.mate.find().count();
7
skip(): 跳過幾筆資料
limit(): 限制回傳筆數
> db.mate.find().skip(2).limit(2);
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
> db.mate.find().skip(3).limit(1);
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
sort: 針對 age 排序
> db.mate.find().sort({age:1});
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
> db.mate.find().sort({age:-1});
{ "_id" : ObjectId("5641980c997bc79c93b12e77"), "userid" : "mary", "username" : "Mary Wang", "city" : "Tainan", "age" : 23, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e79"), "userid" : "lunar", "username" : "Lunar Wang", "city" : "I Lan", "age" : 22, "room" : "302" }
{ "_id" : ObjectId("5641980c997bc79c93b12e75"), "userid" : "john", "username" : "John Lin", "city" : "Taipei", "age" : 20, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e78"), "userid" : "celina", "username" : "Celina Lin", "city" : "Taichung", "age" : 20, "room" : "601" }
{ "_id" : ObjectId("5641980c997bc79c93b12e76"), "userid" : "muder", "username" : "Muder Yen", "city" : "Taichung", "age" : 19, "room" : "301" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7a"), "userid" : "danny", "username" : "Danny Huang", "city" : "Taipei" }
{ "_id" : ObjectId("5641980c997bc79c93b12e7b"), "userid" : "johnny", "username" : "Johnny Lo", "city" : "Taipei", "age" : null }
以下為所有測試的指令
db.mate.save({userid:"john", username:"John Lin", city:"Taipei", age: 20, room:"301"});
db.mate.save({userid:"muder", username:"Muder Yen", city:"Taichung", age: 19, room:"301"});
db.mate.save({userid:"mary", username:"Mary Wang", city:"Tainan", age: 23, room:"601"});
db.mate.save({userid:"celina", username:"Celina Lin", city:"Taichung", age: 20, room:"601"});
db.mate.save({userid:"lunar", username:"Lunar Wang", city:"I Lan", age: 22, room:"302"});
db.mate.save({userid:"danny", username:"Danny Huang", city:"Taipei"});
db.mate.save({userid:"johnny", username:"Johnny Lo", city:"Taipei", age: null});
db.mate.find( {age:{ $gt: 22}} );
db.mate.find( {age:{ $gte: 22}} );
db.mate.find( {age:{ $ne: 22}} );
db.mate.find( {age:{ $mod: [10,0]}} );
db.mate.find( {age:{ $all:[20]}} );
db.mate.find( {age:{ $in:[22, 23]}} );
db.mate.find( {age:{ $nin:[22, 23]}} );
db.mate.find( {age:{$exists:false}} );
db.mate.find( {age:null} );
db.mate.find( {age:{$in:[null], $exists:true}} );
db.mate.find( {username:{ $regex:/^M.*/ }} );
db.mate.find( {username:{ $not:/^M.*/ }} );
f=function() {return this.age>22;}
db.mate.find(f);
db.mate.find().count();
db.mate.find().skip(2).limit(2);
db.mate.find().skip(3).limit(1);
db.mate.find().sort({age:1});
db.mate.find().sort({age:-1});
MapReduce
MongoDB 的 Map, Reduce 函數都可以用 javascript 實作,Map 函數中必須呼叫 emit(key, value),對 collection 中所有紀錄運算過一次之後,再將 {key, [value1, value2, ....]} 傳遞給 reduce 進行處理,最後可再利用 finalize(),針對 reduce 的結果做更進一步的處理。
在 mongo 中,可以用 mapReduce 或是 runCommand 進行 MapReduce,help mr 看到線上的簡略說明
> help mr
See also http://dochub.mongodb.org/core/mapreduce
function mapf() {
// 'this' holds current document to inspect
emit(key, value);
}
function reducef(key,value_array) {
return reduced_value;
}
db.mycollection.mapReduce(mapf, reducef[, options])
options
{[query : <query filter object>]
[, sort : <sort the query. useful for optimization>]
[, limit : <number of objects to return from collection>]
[, out : <output-collection name>]
[, keeptemp: <true|false>]
[, finalize : <finalizefunction>]
[, scope : <object where fields go into javascript global scope >]
[, verbose : true]}
query: 在進行 Map 運算前,先針對 collection 進行一次資料篩檢
sort: 針對 collection 資料排序,可減少 reduce 的處理時間
limit: 限制由 collection 回傳的資料筆數
out: 儲存統計結果的 collection,如果不指定,會放在暫存的 collection 中,連線中斷後,會自動刪除
keeptemp: 是否要保留暫存的 collection
finalize: 對 reduce 的結果再進行一次處理
scope: 指定可在 map, reduce, finalize 中使用的 global 變數
verbose: 顯示詳細的統計時間資訊
首先準備 map 與 reduce function
> mfunction = function() { emit(this.room, 1 )};
function () { emit(this.room, 1 )}
>
> rfunction = function(key, values) {
... var x = 0;
... values.forEach( function(v) { x += v; } );
... return x;
... }
function (key, values) {
var x = 0;
values.forEach( function(v) { x += v; } );
return x;
}
runCommand,並指定輸出到 mate_res
>
> res = db.runCommand( {
... mapreduce:"mate",
... map: mfunction,
... reduce: rfunction,
... out: "mate_res"
... });
{
"result" : "mate_res",
"timeMillis" : 1,
"counts" : {
"input" : 7,
"emit" : 7,
"reduce" : 3,
"output" : 4
},
"ok" : 1
}
>
> db.mate_res.find();
{ "_id" : null, "value" : 2 }
{ "_id" : "301", "value" : 2 }
{ "_id" : "302", "value" : 1 }
{ "_id" : "601", "value" : 2 }
加上一個 finalize 函數,將結果變成 room 與 count
> ffunction = function(key,value) {return {room:key, count:value};}
function (key,value) {return {room:key, count:value};}
> res = db.runCommand( {
... mapreduce:"mate",
... map: mfunction,
... reduce: rfunction,
... out: "mate_res",
... finalize: ffunction
... });
{
"result" : "mate_res",
"timeMillis" : 1,
"counts" : {
"input" : 7,
"emit" : 7,
"reduce" : 3,
"output" : 4
},
"ok" : 1
}
>
> db.mate_res.find();
{ "_id" : null, "value" : { "room" : null, "count" : 2 } }
{ "_id" : "301", "value" : { "room" : "301", "count" : 2 } }
{ "_id" : "302", "value" : { "room" : "302", "count" : 1 } }
{ "_id" : "601", "value" : { "room" : "601", "count" : 2 } }
加上 query,過濾 mate collection,只需要大於等於 22 歲的人
> res = db.runCommand( {
... mapreduce:"mate",
... map: mfunction,
... reduce: rfunction,
... out: "mate_res",
... finalize: ffunction,
... query: {age:{$gte: 22}}
... });
{
"result" : "mate_res",
"timeMillis" : 1,
"counts" : {
"input" : 2,
"emit" : 2,
"reduce" : 0,
"output" : 2
},
"ok" : 1
}
>
> db.mate_res.find();
{ "_id" : "302", "value" : { "room" : "302", "count" : 1 } }
{ "_id" : "601", "value" : { "room" : "601", "count" : 1 } }
以下為測試指令的集合
mfunction = function() { emit(this.room, 1 )};
rfunction = function(key, values) {
var x = 0;
values.forEach( function(v) { x += v; } );
return x;
}
res = db.runCommand( {
mapreduce:"mate",
map: mfunction,
reduce: rfunction,
out: "mate_res"
});
db.mate_res.find();
ffunction = function(key,value) {return {room:key, count:value};}
res = db.runCommand( {
mapreduce:"mate",
map: mfunction,
reduce: rfunction,
out: "mate_res",
finalize: ffunction
});
db.mate_res.find();
res = db.runCommand( {
mapreduce:"mate",
map: mfunction,
reduce: rfunction,
out: "mate_res",
finalize: ffunction,
query: {age:{$gte: 22}}
});
db.mate_res.find();