第一章 前言
1.1 知識體系分析
前端工程師:Web前端,也就是在Web應用中用戶可以看得見碰得著的東西。包括Web頁面的結構、Web的外觀視覺表現以及Web層面的交互實現。
后端工程師:與數據庫進行交互以處理相應的業務邏輯,提供數據供前端顯示。需要考慮的是如何實現功能、數據的存取、平臺的穩定性與性能等。
1.2 mongodb概述
mongodb 是一個基于分布式文件存儲的數據庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。
mongodb 是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。
- 關系型數據庫(sql):數據以表格形式存儲,通過表格的行列關系進行檢索,每一行的內容,必是符合表結構的,就是說--列的個數,類型都一樣.
- 文檔型數據庫(no-sql not-only-sql):數據以文檔類型進行存儲,數據之間沒有嚴格的映射關系.
mongodb是一種文檔形數據庫,數據以key/value形式存儲,內部執行引擎為JS解釋器, 把文檔存儲成bson結構,通過gridefs系統存儲文件,在查詢時,轉換為js對象,并可以通過熟悉的js語法來操作.
第二章 Mongodb在windows下的安裝
2.1 mongodb的安裝
- 下載最新stable版的mongodb
www.mongodb.org
; - 不需要編譯,一路next安裝
2.2 目錄結構
- bsondump: binary-json,二進制文件,選擇性導出bson文件
- mongo: 客戶端
- mongod: 服務端
- mongodump: 整體導出數據庫(二進制)
- mongoexport:導出易識別的json文檔
- mongoimport:導入json文檔
- mongorestore:數據庫整體導入
- mongos: 路由器(分片)
2.3 啟動mongod服務
./bin/mongod.exe --dbpath /path/to/database --logpath /path/to/log-file --port 27017
參數解釋:
- dbpath 數據存儲目錄
- logpath 日志存儲文件
- port 運行端口(默認27017)
打開localhost:27017
頁面,可以看到以下信息:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
證明服務器啟動成功.
然后另外開啟一個命令窗口,執行mongo.exe
,進入mongodb客戶端.
2.4 基本概念解釋
MongoDB術語/概念 | 解釋/說明 |
---|---|
database | 數據庫 |
collection | 數據庫表/集合 |
document | 數據記錄行/文檔 |
field | 數據字段/域 |
index | 索引 |
primary key | 主鍵,MongoDB自動將_id字段設置為主鍵 |
第三章 Mongodb入門命令
3.1 基本查看命令
- show dbs 查看當前的數據庫
- use databaseName 選庫
- show tables/collections 查看當前庫下的collection
3.2 庫和collection的操作
db
查看當前所處的數據庫在mongodb中,庫是隱式創建,
你可以use 一個不存在的庫, 然后在該庫下創建collection,即可創建庫db.dropDatabase();
刪除databasedb.createCollection(‘collectionName’)
創建collectioncollection也是允許隱式創建的
db.collectionName.insert(document);
在集合(表)中插入具體數據的時候會自動創建db.collectionName.drop() ,
刪除collection
第四章 Mongodb基本增刪改查操作
4.1 增加數據
mongodb存儲的是文檔,文檔是json格式的對象,我們向數據庫存儲數據的時候可以使用insert方法,數據格式要以js對象格式進行存儲:
語法:db.collectionName.insert(document)
;
我們可以以多種方法對文檔進行存儲:
4.1.2 增加單篇文檔
db.collectionName.insert({title:"nice day"});
4.1.3 增加單個文檔,并且指定_id
_id
是我們在插入數據的時候,mongodb自動給文檔添加的一個屬性,如果我們不需要系統分配_id
,可以在添加數據的時候手動設置,覆蓋原有_id
,雖然_id
的類型可以自由指定,但是在同一個集合當中必須唯一,如果插入重復的值,系統會拋出異常.
這個
_id
的名稱是固定的,它可以是Mongodb支持的任何數據類型,默認是ObjectId,在關系型數據庫中,主鍵通常是數值型的,并且可以設置自增,反觀Mongodb的主鍵,原生不支持自增主鍵.
db.collectionName.insert({_id:8,age:78,name:"lisi"});
> db.stu.insert({_id:3,age:17})
WriteResult({ "nInserted" : 1 })
> db.stu.insert({_id:3,age:14})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: web.students index: _id_ dup key: { : 3.0 }"
}
})
4.1.4 增加多個文檔
db.collectionName.insert(
[
{time:'friday',study:'mongodb'},
{_id:9,gender:'male',name:'QQ'}
]
)
可以以數組的方式,一次性向集合插入多個數據;
同時應該注意的是,由于mongodb采用的是JavaScript Shell
,所以我們可以根據js特性,將文檔作為值賦給變量然后進行操作:
j = {name : "mongo"};
t = {x:3};
db.stu.insert([j,t]);
4.1.5 save和insert的區別
save和insert都可以進行數據的插入和增加,但是也有一些異同:
對于已存在數據{_id:1, "name":"n1"}
,再次進行插入操作時,insert({_id : 1, "name" :"n2"})
會報主鍵重復的錯誤提示save({ _id:1, " name ":"n2"})
會把n1修改為n2。
相同點:
若新增的數據中沒有主鍵時,會增加一條記錄。
4.2 查詢操作
4.2.1 find()
無條件的普通查詢方式很簡單,可以直接使用
db.collectionName.find();
一次可以查出指定集合中的所有數據
for(var i = 1;1<10;i++) db.stu.save({x:4,y:3});
db.stu.find();
如果出現顯示不全的現象,可以使用"it"命令,繼續顯示下面的數據.
當然,我們還可以按照條件進行查詢操作
語法: db.collection.find(查詢表達式,查詢的列);
例1: db.stu.find({},{gendre:1})
查詢所有文檔,的gender屬性 (_id屬性默認總是查出來)
例2: db.stu.find({},{gender:1, _id:0})
查詢所有文檔的gender屬性,且不查詢_id屬性
此處的0表示的是false,不查詢
例3: db.stu.find({gender:’male’},{name:1,_id:0});
查詢所有gender屬性值為male的文檔中的name屬性
4.2.2 findOne()
findOne()和find()函數一樣,只是findOne()返回的是查詢結果中的第一條數據,或者返回null.
db.stu.findOne(查詢表達式,查詢的列)
4.3 刪除操作
語法: db.collectionName.remove(查詢表達式, 選項);
選項是指 {justOne:true/false}
,是否只刪一行, 默認為false
注意
- 1: 查詢表達式依然是個json對象
- 2: 查詢表達式匹配的行,將被刪掉.
- 3: 如果查詢表達式為空對象{},collections中的所有文檔將被刪掉.
例1: db.stu.remove({sn:'001'})
;
刪除stu表中sn屬性值為'001'的文檔
例2: db.stu.remove({gender:'m'},true)
;
刪除stu表中gender屬性為m的文檔,只刪除1行.
4.4 修改操作
語法: db.collection.update(查詢表達式,新值,選項);
* 改哪幾行? --- 查詢表達式
* 改成什么樣? -- 新值 或 賦值表達式
* 操作選項 ----- 可選參數
upsert:如果要更新的那條記錄沒有找到,是否插入一條新紀錄,默認為false
multi :是否更新滿足條件的多條的記錄,默認為false
multi :是否更新滿足條件的多條的記錄,false:只更新第一條,true:更新多條,默認為false
例:db.news.update({name:'QQ'},{name:'MSN'})
;
是指選中news表中,name值為QQ的文檔,并把其文檔值改為{name:"MSN"},
結果: 文檔中的其他列也不見了,改后只有_id和name列了.即是新文檔直接覆蓋了舊文檔,而不是修改.
4.4.1 修改操作中的關鍵字
如果是想修改文檔的某列,可以用$set
關鍵字
db.collectionName.update(query,{$set:{name:’QQ’}})
修改時的賦值表達式
- $set 修改某列的值
- $unset 刪除某個列
- $inc 增長某個列
- $rename 重新命名某列
- $setOnInsert 當upsert為true時,并且發生了insert操作時,可以補充的字段.
$inc實例
按照指定的步長增長某個列;
> db.stu.insert({"uid":"201203","type":"1",size:10})
> db.stu.find()
{ "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1",
"size" : 10 }
> db.stu.update({"uid" : "201203"},{"$inc":{"size" : 2}})
> db.stu.find()
{ "_id" : ObjectId("5003b6135af21ff428dafbe6"), "uid" : "201203", "type" : "1",
"size" : 12 }
$unset實例
>db.stu.find({_id:3})
{"_id" : 3 , "age" : 18}
> db.stu.update({_id:3},{$unset:{age:'sss'}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.stu.update({_id:3},{$unset:{age:'sss'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.stu.find({_id:3})
{ "_id" : 3 }
$rename實例
->db.stu.insert({name:'lisi',age:12,sex:'male',height:123,area:'haidian'});
->db.stu.update({name:'lisi'},{$set:{area:'chaoyang'},$unset:{height:1},$inc:{age:1},$rename:{sex:'gender'}});
4.4.2 Option選項的作用:
{upsert:true/false,multi:true/false}
- upsert:是指沒有匹配的行,則直接插入該行
例:db.stu.update({name:'wuyong'},{$set:{name:'junshiwuyong'}},{upsert:true});
如果有name='wuyong'
的文檔,將被修改,如果沒有,將添加此新文檔
例:db.news.update({_id:99},{x:123,y:234},{upsert:true});
沒有_id=99的文檔被修改,因此直接插入該文檔
- multi: 是指修改多行(即使查詢表達式命中多行,默認也只改1行,如果想改多行,可以用此選項)
例:db.news.update({age:21},{$set:{age:22}},{multi:true});
則把news中所有age=21的文檔,都修改
4.5 查詢表達式
我們無論在修改刪除還是查詢的過程中,都需要傳入查詢表達式對目標數據進行查詢,表達式有很多種
1: 最簡單的查詢表達式
{filed:value} ,是指查詢field列的值為value的文檔
2: $ne:!=
{field:{$ne:value}}
db.stu.find({age:{$ne:16}})
作用--查age列的值 不等于16的文檔
3:$gt:大于
$lt:小于
$gte:大于或等于
$lte:小于或等于
4: $in:[]
查詢某列的值在范圍內的文檔
db.goods.find({cat_id:{$in:[2,8]}}
5: $nin:not in
查詢某列不在范圍內的文檔
$nin:[2,3,5]
6: $exists
語法: {field:{$exists:1}}
作用: 查詢出含有field字段的文檔
7:用正則表達式查詢 以”諾基亞”開頭的商品
例:db.goods.find({goods_name:/諾基亞.*/},{goods_name:1});
第五章 游標操作
通俗的說,游標不是查詢結果,而是查詢的返回資源,或者接口,通過這個接口,你可以逐條對數據進行讀取;
聲明游標:
var cursor = db.collectioName.find(query,projection);
cursor.hasNext() //判斷游標是否已經取到盡頭
cursor.next() //取出游標的下1個單元
用while來循環游標
> var mycursor = db.bar.find({_id:{$lte:5}})
> while(mycursor.hasNext()) {
printjson(mycursor.next());
}
游標還有一個迭代函數,允許我們自定義回調函數來逐個處理每個單元.
cursor.forEach(回調函數);
> var gettitle = function(obj) {print(obj.goods_name)}
> var cursor = db.goods.find();
> cursor.forEach(gettitle);
游標在分頁中的應用
比如查到10000行,跳過100頁,取10行,一般地,我們假設每頁N行, 當前是page頁,就需要跳過前 (page-1)*N 行, 再取N行.
在mongo中,分頁是用skip(), limit()函數來實現的
//查詢結果中,跳過前9995行
var mycursor = db.bar.find().skip(9995);
//查詢第901頁,每頁10條
則是 var mytcursor = db.bar.find().skip(9000).limit(10);
第六章 MongoDB在Node環境中使用
我們如果想要將mongodb用于實際的開發中于nodejs作為交互,需要下載node下的mongodb服務器模塊.
在項目根目錄下運行
npm install mongodb --save
安裝完畢后啟動mongodb的服務端mongod.exe,我們就可以通過js代碼的形式鏈接mongodb數據庫了
6.1 快速開始
官方API地址:http://mongodb.github.io/node-mongodb-native/2.2/quick-start/quick-start/
var myClient = require('mongodb').MongoClient;
var server = 'mongodb://localhost:27017/web';//連接web集合
myClient.connect(server,function(err,db){//連接數據庫
if(!err){
console.log(db);
db.close(); //關閉數據庫
}
})
6.2 增加數據
插入數據有insertOne和insertMany兩種方法
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').insertOne({a:1}, function(err, res) {
//insertOne插入一條數據
console.log(res.insertedCount);
//返回值對象里的insertedCount表示插入數量
});
db.collection('inserts').insertMany([{a:2},{a:3}], function(err, res) {
//insertOne插入多條數據
console.log(res.insertedCount);
db.close();
});
});
6.3 查詢數據
查詢所有的文檔數據
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').find({}).toArray(function(err,docs){
if(!err){
console.log(docs);
}
db.close();
});
});
當然,我們可以使用條件查詢數據
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').find({a:{$ne:2}}).toArray(function(err, docs) {
if (!err) {
console.log(docs);
}
db.close();
});
});
查詢數據的過程中,我們同樣可以使用skip()
,limit()
等方法
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').find({a:{$ne:2}}).skip(4).limit(2).toArray(function(err, docs) {
if (!err) {
console.log(docs);
}
db.close();
});
});
查詢過程中的連續操作
在查詢的過程中,給我們提供了三個連續操作的API findOneAndUpdate
, findOneAndDelete
, findOneAndReplace
,使用起來也非常方便
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').findOneAndUpdate({a:1},{$set:{b:3}},function(err,res){
console.log(res);
});
db.close();
});
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').findOneAndDelete({b:3},function(err,res){
console.log(res);
});
db.close();
});
6.4 刪除操作
我們可以使用deleteOne和deleteMany方法刪除collection中的數據
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').deleteOne({a:1},function(err,res){
console.log(res.deletedCount);
});
db.close();
});
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').deleteMany({a:2},function(err,res){
console.log(res.deletedCount);
});
db.close();
});
6.5 修改操作
同樣,update操作也可以使用updateOne和updateMany兩種方法,在修改的同時也可以使用查詢表達式.
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').updateOne({a:1},{$set:{b:2}},function(err,res){
console.log(res.modifiedCount);
});
db.close();
});
{upsert: true}
幫助我們在修改不存在的數據時插入一條新數據`
注意
如果按照"_id"進行查詢或者修改的話,直接填入_id
的值是不能獲取結果的,因為mongodb的_id
默認值是ObjectId類型的
var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').find({_id:"58b04104ae7db136d00ebb66"}).toArray(function(err, docs) {
if (!err) {
console.log(docs);
}
db.close();
});
});
會發現方法正確但是沒有返回值;如果我們想要按照主鍵查找,需要引入Object模塊:
var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectId;
var url = 'mongodb://localhost:27017/web';
MongoClient.connect(url, function(err, db) {
db.collection('inserts').find({_id:ObjectId("58b04104ae7db136d00ebb66")}).toArray(function(err, docs) {
if (!err) {
console.log(docs);
}
db.close();
});
});