1 前言
MongoDB是一個基於分散式檔案儲存的開源資料庫系統。
MongoDB 將資料儲存為一個文件,資料結構由鍵值(key=>value)對組成。MongoDB 文件類似於 JSON 物件。欄位值可以包含其他文件,陣列及文件陣列。
2 安裝(mac)
- 安裝homebrew
- 使用brew安裝mongodb
brew install mongodb
複製程式碼
- 視覺化工具 Robomongo
3 mongodb啟動與連線(mac)
3.1 服務端啟動
3.1.1 啟動步驟
-
- 在要啟動的目錄下新建一個目錄(如:
data
)
- 在要啟動的目錄下新建一個目錄(如:
mkdir data
複製程式碼
-
- 命令列中輸入(–dbpath引數指定資料庫路徑)
mongod --dbpath=`./data`
複製程式碼
如果出現waiting for connections on port 27017
就表示啟動成功。
注意:這個命令窗體絕對不能關,關閉這個視窗就相當於停止了mongodb服務
3.1.2 mongod
啟動命令mongod引數說明
選項 | 含義 |
---|---|
–port | 指定服務埠號,預設埠27017 |
–logpath | 指定MongoDB日誌檔案,注意是指定檔案不是目錄 |
–logappend | 使用追加的方式寫日誌 |
–dbpath | 指定資料庫路徑 |
–directoryperdb | 設定每個資料庫將被儲存在一個單獨的目錄 |
3.2 客戶端啟動
- 命令列輸入
mongo
複製程式碼
也可以設定host
mongo --host 127.0.0.1
複製程式碼
4 MongoDB基本概念
資料庫
MongoDB的單個例項可以容納多個獨立的資料庫,比如一個學生管理系統就可以對應一個資料庫例項。集合
資料庫是由集合組成的,一個集合用來表示一個實體,如學生集合。文件
集合是由文件組成的,一個文件表示一條記錄,比如一位同學張三就是一個文件
對應關係如下圖:
5 資料庫操作
5.1 檢視所有資料庫
show dbs
複製程式碼
返回如下:
admin 0.000GB
book 0.000GB
leave 0.000GB
local 0.000GB
page 0.000GB
school 0.000GB
students 0.000GB
複製程式碼
5.2 使用資料庫
例項 切換到 school資料庫下:
use school
複製程式碼
返回如下:
switched to db school
複製程式碼
注:如果此資料庫存在,則切換到此資料庫下,如果此資料庫還不存在也可以切過來
注: 我們剛建立的資料庫school如果不在列表內,要顯示它,我們需要向school資料庫插入一些資料
db.school.insert({name:`為民小學`,age:10});
複製程式碼
5.3 檢視當前使用的資料庫
db 或 db.getName()
複製程式碼
5.4 刪除資料庫
db.dropDatabase()
複製程式碼
返回如下:
{ "dropped" : "school", "ok" : 1 }
複製程式碼
6 集合操作
6.1 檢視集合幫助
db.school.help()
複製程式碼
返回如下:
BCollection help
db.school.find().help() - show DBCursor help
db.school.bulkWrite( operations, <optional params> ) - bulk execute write ...
複製程式碼
6.2 檢視資料庫下的集合
show collections
複製程式碼
返回如下:
grade1
grade2
複製程式碼
6.3 建立集合
- 建立一個空集合(
db.createCollection(collection_Name)
)
db.createCollection(`grade3`)
複製程式碼
返回如下:
{ "ok" : 1 }
複製程式碼
- 建立集合並插入一個文件(
db.collection_Name.insert(document)
)
db.grade1.insert({name: `Lily`, age: 8})
複製程式碼
返回如下:
WriteResult({ "nInserted" : 1 })
複製程式碼
7 文件操作
7.1 插入文件
insert
db.collection_name.insert(document)
db.grade1.insert({name: `Tom`, age: 9})
複製程式碼
note:每當插入一條新文件的時候mongodb會自動為此文件生成一個_id屬性,_id一定是唯一的,用來唯一標識一個文件 _id也可以直接指定,但如果資料庫中此集合下已經有此_id的話插入會失敗。
{
"_id" : ObjectId("5addbfbb163098017a6a72ed"),
"name" : "Tom",
"age" : 9.0
}
複製程式碼
save
db.collection_name.save(document)
note:如果不指定 _id 欄位 save() 方法類似於 insert() 方法。如果指定 _id 欄位,則會更新該 _id 的資料。
// insert
db.grade1.insert({_id: `1`,name: `Han Meimei`, age: 8})// WriteResult({ "nInserted" : 1 })
// 存在{_id:1},則更新 _id為1的document
db.grade1.save({_id: `1`,name: `Han Meimei`, age: 9})// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 不存在{_id:2},則插入一條新文件
db.grade1.save({_id: `2`,name: `Han Meimei`, age: 9})// WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : "2" })
複製程式碼
執行指令碼插入
mongo exc_js/1.js
> load exc_js/1.js
複製程式碼
7.2 更新文件
7.2.1 語法 & 引數說明
db.collection.update(
<query>,
<updateObj>,
{
upsert: <boolean>,
multi: <boolean>
}
)
複製程式碼
query
查詢條件,指定要更新符合哪些條件的文件update
更新後的物件或指定一些更新的操作符$set
直接指定更新後的值$inc
在原基礎上累加
upsert
可選,這個引數的意思是,如果不存在符合條件的記錄時是否插入updateObj. 預設是false,不插入。multi
可選,mongodb 預設只更新找到的第一條記錄,如果這個引數為true,就更新所有符合條件的記錄。
7.2.2 操作符
(1) $inc
{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }
- 在原基礎上累加(increment)
// 給 {name: `Tom`} 的文件的age累加 10
db.grade1.update({name: `Tom`}, {$inc: {age:10}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
複製程式碼
(2) $push
{ $push: { <field1>: <value1>, ... } }
- 向陣列中新增元素
db.grade1.update({name:`Tom`}, {$push: {`hobby`:`reading`} })
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// { "_id" : ObjectId("5addbfbb163098017a6a72ed"), "name" : "Tom", "hobby" : [ "reading" ] }
// 不會覆蓋已有的
db.grade1.update({name:`Tom`}, {$push: {`hobby`:`reading`} })
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// { "_id" : ObjectId("5addbfbb163098017a6a72ed"), "name" : "Tom", "hobby" : [ "reading", "reading" ] }
複製程式碼
(3) $addToSet
{ $addToSet: { <field1>: <value1>, ... } }
- 給陣列新增或者設定一個值,
- 有 – do nothing, 沒有 – 新增
// /第一次沒有 huge
db.grade1.update({_id:3}, {$addToSet: {friends:`huge`}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 第二次 有 huge
db.grade1.update({_id:3}, {$addToSet: {friends:`huge`}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
複製程式碼
(4) $pop
{ $pop: { <field>: <-1 | 1>, ... } }
- 刪除陣列的第一個或者最後一個元素。
- 傳入
1
刪除最後一個元素 - 傳入
-1
刪除第一個元素
db.grade1.update({_id:3}, {$pop:{friends: 1}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
db.grade1.update({_id:3}, {$pop:{friends: -1}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
複製程式碼
(5) $each
{ $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }
- Use with the $addToSet operator to add multiple values to an array if the values do not exist in the .
db.grade1.update({_id:3}, {$addToSet:{friends:{$each: [`huangbo`,`zhangyixing`]}}})
//WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 已經有的時候就不會再新增了
db.grade1.update({_id:3}, {$addToSet:{friends:{$each: [`huangbo`,`zhangyixing`]}}})
//WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
複製程式碼
{ $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }
- Use with the $push operator to append multiple values to an array .
db.grade1.update({_id:3}, {$push:{friends:{$each: [`huangbo`,`zhangyixing`]}}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
複製程式碼
在
$addToSet
中使用時,若有則忽略,若沒有則新增。在$push
中使用時,不管有沒有都會新增。
(6) $ne
{field: {$ne: value} }
- not equal
// 給 name為`Han Meimei` && hobby中不等於`reading` && _id不等於`2`的文件 的hobby 屬性 新增一個 `drinking`
db.grade1.update({name: `Han Meimei`, hobby:{$ne:`reading`}, _id: {$ne:`2`}}, {$push: {hobby: `drinking`}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
複製程式碼
(7)$set
{ $set: { <field1>: <value1>, ... } }
- 設定欄位的第一層的值(Set Top-Level Fields)
- 設定巢狀欄位的值 (Set Fields in Embedded Documents)
- 修改指定索引元素
/*
原來的資料:
{_id:3, info:{id: `11`}, friends:[`liudehua`, `zhourunfa`]}
*/
/*設定欄位的第一層的值(Set Top-Level Fields)*/
db.grade1.update({_id:3}, {$set:{"info11":{id:`11`}}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
/*設定巢狀欄位的值 (Set Fields in Embedded Documents)*/
db.grade1.update({_id:3}, {$set:{"info.id":`22`}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
/*修改指定索引元素*/
db.grade1.update({_id:3}, {$set:{"friends.1":`zhangmanyu`}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
複製程式碼
(8) $unset
{ $unset: { <field1>: "", ... } }
- 刪除指定的鍵
// 把 {name: `Tom`} 的文件中的 age 鍵給刪除掉
db.grade1.update({name: `Tom`}, {$unset:{`age`:``}})
// WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
/* {
"_id" : ObjectId("5addbfbb163098017a6a72ed"),
"name" : "Tom"
}*/
複製程式碼
7.3 刪除文件
- remove方法是用來移除集合中的資料
語法
db.collection.remove(
<query>,
{
justOne: <boolean>
}
)
複製程式碼
引數說明
query :(可選)刪除的文件的條件。
justOne : (可選)如果設為 true 或 1,則只刪除匹配到的多個文件中的第一個。預設為 true
複製程式碼
/*{justOne:true} 值刪除匹配到的第一條文件*/
db.grade1.remove({`name`: `Han Meimei`}, {justOne: true})
// WriteResult({ "nRemoved" : 1 })
/*刪除匹配到的所有文件*/
db.grade1.remove({`name`: `Han Meimei`})
// WriteResult({ "nRemoved" : 2 })
複製程式碼
7.4 查詢文件
7.4.1
語法
db.collection_name.find(query, projection);
複製程式碼
引數
query - 使用查詢操作符指定選擇過濾器
projection - 指定配到到的文件中的返回的欄位。
複製程式碼
/*projection*/
{ field1: <value>, field2: <value> ... }
/*value:*/
1 or true: 在返回的文件中包含這個欄位
0 or false:在返回的文件中排除這個欄位
複製程式碼
note:
_id
欄位預設一直返回,除非手動將_id
欄位設定為0
或false
舉個例子
//查詢grade1下所有的文件
db.grade1.find()
複製程式碼
7.4.2 findOne()
- 只返回匹配到的第一條文件
7.4.3 查詢操作符
(1) $in
- Matches any of the values specified in an array.
- (在陣列範圍內的)
//原始資料():
{ "_id" : 1, "name" : "Tom1", "age" : 9 }
{ "_id" : 2, "name" : "Tom2", "age" : 15 }
{ "_id" : 3, "name" : "Tom3", "age" : 11 }
複製程式碼
db.grade1.find({age:{$in:[9,11]}})
// { "_id" : 1, "name" : "Tom1", "age" : 9 }
// { "_id" : 3, "name" : "Tom3", "age" : 11 }
複製程式碼
(2) $nin
- Matches none of the values specified in an array.
db.grade1.find({age:{$nin:[9,11]}})
// { "_id" : 2, "name" : "Tom2", "age" : 15 }
複製程式碼
(3) $not
- Inverts the effect of a query expression and returns documents that do not match the query expression.
db.grade1.find({age:{$not:{$lt:11}}})
//{ "_id" : 2, "name" : "Tom2", "age" : 15 }
//{ "_id" : 3, "name" : "Tom3", "age" : 11 }
複製程式碼
(4) $gt
- Matches values that are greater than a specified value.
- 大於
(5) $gte
- Matches values that are greater than or equal to a specified value.
- 大於等於
(6) $lt
- Matches values that are less than a specified value.
- 小於
(7) $lte
- Matches values that are less than or equal to a specified value.
- 小於等於
(8)$ne
- Matches all values that are not equal to a specified value.
- 不等於
db.grade1.find({age:{$ne:9}})
// { "_id" : 2, "name" : "Tom2", "age" : 15 }
// { "_id" : 3, "name" : "Tom3", "age" : 11 }
複製程式碼
7.4.4 陣列的用法
// 原始資料
{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }
複製程式碼
db.grade1.find({"friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ]})
// { "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
db.grade1.find({"friends" : [ "Lily" ]})
// 空
// $all
db.grade1.find({"friends" :{$all: ["Zhang San"]}})
// { "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
// $in
db.grade1.find({"friends" :{$in: ["Zhang San"]}})
{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
// $size
db.grade1.find({"friends" :{$size:4}})
//{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
// $slice
db.collection.find( { field: value }, { array: {$slice: count } } );
> db.grade1.find({"friends" :{$size:4}}, {"friends":{$slice:2}})
//{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs" ] }
複製程式碼
7.4.5 $where
-
$where
可以接收兩種引數傳遞給查詢系統,一種是包含JavaScript表示式的字串,另外一種是JavaScript函式。 -
$where
非常靈活,但是它需要資料庫集合中的每一個文件中處理這個JavaScript表示式或者JavaScript函式,所以會比較慢。 -
在JavaScript表示式或者JavaScript函式中引用文件的時候,可是使用
this
或者obj
。
// 資料庫資料
{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }
// JS表示式的字串
> db.grade1.find({$where:`this.name == "Tom1"`})
//{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
// 函式
> db.grade1.find({$where: function(){return this.age == 9}})
// { "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
複製程式碼
7.4.6 Cursor Methods
這些方法改變了執行基礎查詢方式。
包括cursor.forEach()
、cursor.map()
、cursor.limit()
、cursor.size()
、cursor.count()
等。
// forEach舉例
> var result = db.grade1.find({$where: function(){return this.age >= 9}});
> result.forEach(elem => printjson(elem))
/*{
"_id" : 1,
"name" : "Tom1",
"age" : 9,
"friends" : [
"Lily",
"Jobs",
"Lucy",
"Zhang San"
]
}
{
"_id" : 2,
"name" : "Tom2",
"age" : 15,
"friends" : [
"Zhange San",
"Li Si"
]
}
{
"_id" : 3,
"name" : "Tom3",
"age" : 11,
"friends" : [
"Zhange San",
"Lily"
]
}*/
複製程式碼
8 條件操作符
8.1 條件操作符
$gt
– 大於$gte
– 大於等於$lt
– 小於$lte
– 小於等於
// 大於等於
db.grade1.find({age:{$gte:9}})
/*{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }*/
// 大於等於9 並且 小於等於13
db.grade1.find({age:{$gte:9}, age: {$lte:13}})
/*{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }*/
複製程式碼
8.2 使用_id進行查詢
//原始資料
{ "_id" : ObjectId("5ae1b6e3e4366d57f3307239"), "name" : "Tom4" }
> db.grade1.find({_id: `5ae1b6e3e4366d57f3307239`}).count()
// 0
> db.grade1.find({_id:ObjectId(`5ae1b6e3e4366d57f3307239`)}).count()
// 1
複製程式碼
count()
查詢結果的條數
8.3 正則匹配
db.collection.find({key:/value/})
// name是以`T`開頭的資料
db.grade1.find({name: /^T/})
/*{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }
{ "_id" : ObjectId("5ae1b6e3e4366d57f3307239"), "name" : "Tom4" }*/
複製程式碼
9 與和或
9.1 and
db.collection_name.find({field1: value1, field2:value2})
//原始資料
{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }
複製程式碼
// and name是以‘T’開頭 並且 age是9 的資料
> db.grade1.find({name: /^T/, age: 9})
// { "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
複製程式碼
9.2 or
db.collection_name.find({ $or: [{key1: value1}, {key2:value2} ] })
// name 是Tom1 或者 age是11 的資料
> db.grade1.find({$or:[{name: `Tom1`}, {age: 11}]})
/*{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }
{ "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }*/
複製程式碼
9.3 and 和 all 聯合使用
> db.grade1.find({age: 9,$or:[{name: `Tom1`}, {age: 11}]})
/*{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] }*/
複製程式碼
10 分頁查詢
10.1 limit
- 讀取指定數量的資料記錄 語法
db.collectoin_name.find().limit(number)
10.2 skip
- 跳過指定數量的資料
db.collectoin_name.find().skip(number)
10.3 sort
-通過引數指定排序的欄位,並使用 1 和 -1 來指定排序的方式,其中 1為升序排列,而-1是用於降序排列。
db.collectoin_name.find().sort({field:1})
db.collectoin_name.find().sort({field:-1})
10.4 分頁
// 原始資料為 1 2 3 4 5 6 7 8 9
> var pageIndex = 3;
> var pageSize = 3;
> var res = db.grade1.find({}).skip((pageIndex - 1) * pageSize).limit(pageSize).sort({username: 1});
> res
/*{ "_id" : ObjectId("5ae1cbc609f3ac9a41442546"), "username" : "Lily_7", "password" : 7 }
{ "_id" : ObjectId("5ae1cbc609f3ac9a41442547"), "username" : "Lily_8", "password" : 8 }
{ "_id" : ObjectId("5ae1cbc609f3ac9a41442548"), "username" : "Lily_9", "password" : 9 }*/
var res1 = db.grade1.find().skip((pageIndex - 1) * pageSize).limit(pageSize).sort({username: -1});
/*{ "_id" : ObjectId("5ae1cbc609f3ac9a41442542"), "username" : "Lily_3", "password" : 3 }
{ "_id" : ObjectId("5ae1cbc609f3ac9a41442541"), "username" : "Lily_2", "password" : 2 }
{ "_id" : ObjectId("5ae1cbc609f3ac9a41442540"), "username" : "Lily_1", "password" : 1 }*/
複製程式碼
note: 沒有先後順序
11 ObjectId構成
之前我們使用MySQL等關係型資料庫時,主鍵都是設定成自增的。但在分散式環境下,這種方法就不可行了,會產生衝突。為此,MongoDB採用了一個稱之為ObjectId的型別來做主鍵。ObjectId是一個12位元組的 BSON 型別字串。按照位元組順序,一次代表:
- 4位元組:UNIX時間戳
- 3位元組:表示執行MongoDB的機器
- 2位元組:表示生成此_id的程式
- 3位元組:由一個隨機數開始的計數器生成的值