4.3.2 中間件的原理
中間件就是一個(gè)函數(shù)抡秆,它能夠訪問請(qǐng)求對(duì)象?(req)徒坡、響應(yīng)對(duì)象?(res) 以及應(yīng)用程序的請(qǐng)求/響應(yīng)循環(huán)中的下一個(gè)中間件函數(shù)潮秘。下一個(gè)中間件函數(shù)通常由名為 next 的變量來(lái)表示澄者。
中間件中可以執(zhí)行任意代碼抚笔,但主要執(zhí)行以下任務(wù):
對(duì)請(qǐng)求和響應(yīng)對(duì)象進(jìn)行更改扶认。
結(jié)束請(qǐng)求/響應(yīng)循環(huán)。
調(diào)用堆棧中的下一個(gè)中間件函數(shù)殊橙。
如果當(dāng)前中間件函數(shù)沒有結(jié)束請(qǐng)求/響應(yīng)循環(huán)辐宾,那么它必須調(diào)用 next()狱从,以將控制權(quán)傳遞給下一個(gè)中間件函數(shù)。否則叠纹,請(qǐng)求將保持掛起狀態(tài)季研。
4.3.3 中間件的使用方法
使用 app.use() 和 app.[METHOD]() 函數(shù)將應(yīng)用層中間件綁定到應(yīng)用程序?qū)ο?/a>的實(shí)例,其中 METHOD 是中間件函數(shù)處理的請(qǐng)求的小寫 HTTP 方法(例如 get誉察、put 或 post)与涡。
var app = express();
app.use(function (req, res, next) {
? console.log('Time:', Date.now());
? next();
});
// 在 /user/:id 路徑中為任何類型的 HTTP 請(qǐng)求執(zhí)行此中間件函數(shù)
// 中間件可以傳遞多個(gè),用于順序調(diào)用持偏。
app.use('/user/:id', function (req, res, next) {
? console.log('Request Type:', req.method);
? next();
}, function (req, res, next) {
? console.log('Request Type:', req.method);
? next();
});
// 在/user/:id 路徑中為 GET 請(qǐng)求執(zhí)行此中間件函數(shù)
app.get('/user/:id', function (req, res, next) {
? res.send('USER');
? //此時(shí)請(qǐng)求已經(jīng)完成
});
// 要跳過路由器中間件堆棧中剩余的中間件函數(shù)驼卖,請(qǐng)調(diào)用 next('route') 將控制權(quán)傳遞給下一個(gè)路由。
// 注:next('route') 僅在使用 app.METHOD() 或 router.METHOD() 函數(shù)裝入的中間件函數(shù)中有效鸿秆。
app.get('/user/:id', function (req, res, next) {
? // if the user ID is 0, skip to the next route
? if (req.params.id == 0) next('route');
? // otherwise pass the control to the next middleware function in this stack
? else next(); //
}, function (req, res, next) {
? // render a regular page
? res.render('regular');
});
// if the user ID is 0,this route will execute.
app.get('/user/:id', function (req, res, next) {
? res.render('special');
});
注意點(diǎn):
Express 使用?path-to-regexp?來(lái)匹配路由路徑酌畜。匹配規(guī)則:
/abc/:id:匹配/abc/1,/abc/xf卿叽,/abc/桥胞,其中:id表示任意參數(shù),但它必須是子路徑考婴。
/abc?d:匹配abcd或者abd贩虾,其中c?表示c可有可無(wú)。
/ab+cd:匹配abcd沥阱,abbbcd缎罢,其中b+表示可以任意一個(gè)或多個(gè)。
/ab\*cd:匹配abcd喳钟,abicd屁使,其中\(zhòng) *表示任意值。
path中也可以存放數(shù)組奔则,表示匹配每一項(xiàng)蛮寂。
app.all():用于為express或者路由增加中間件,"/"會(huì)匹配多種地址或者子地址易茬。
app.all():用于匹配express或者路由任意請(qǐng)求酬蹋,"/"只會(huì)匹配精確地址。
res.send():電風(fēng)扇
會(huì)自動(dòng)為內(nèi)容設(shè)置Content-Type,如果傳遞文本抽莱,則設(shè)置text/html范抓。
res.send() 只能調(diào)用一次,調(diào)用完畢會(huì)自動(dòng)調(diào)用res.end()食铐,如果想多次輸出匕垫,可以使用res.write。
4.3.4 常用中間件
1. 路由器層中間件
路由器層中間件的工作方式與應(yīng)用層中間件基本相同虐呻。
// index.js
const express = require('express')
const router = require('./router')
const app = express()
app.use(router)
app.listen(3000, () => {
? ? console.log('服務(wù)器創(chuàng)建完畢,監(jiān)聽3000端口')
})
//router.js
const express = require('express')
const router = express.Router()
router.all('/', (req, res, next) => {
? ? res.send('你壞')
? ? next()
})
router.all('/user/:id', (req, res, next) => {
? ? if (req.params.id == 0) {
? ? ? ? next('route')
? ? } else if (req.params.id == 1) {
? ? ? ? res.send('我是老大')
? ? } else {
? ? ? ? res.set({
? ? ? ? ? ? 'Content-Type': 'text/html',
? ? ? ? })
? ? ? ? res.write('我是明明')
? ? ? ? res.write('abcd')
? ? ? ? res.end()
? ? ? ? next()
? ? }
}, (req, res, next) => {
? ? console.log('下一個(gè)中間件')
})
router.use('/user/:id', (req, res, next) => {
? ? res.send('超級(jí)管理員')
})
module.exports = router
2. body和querystring的轉(zhuǎn)換
req中接收到的body默認(rèn)是一個(gè)字符串象泵,我們?cè)谝话銉A向于把它轉(zhuǎn)換成一個(gè)json對(duì)象來(lái)使用寞秃。
使用第三方中間件body-parser可以為req做轉(zhuǎn)換,bodyParser除了可以將body轉(zhuǎn)換成json外偶惠,還可以轉(zhuǎn)換成其他格式春寿。
bodyParser.json():只有請(qǐng)求的Header的Content-Type包含text/json,并且body確實(shí)是json數(shù)據(jù)才會(huì)轉(zhuǎn)換成功忽孽,否則得到的req.body是空對(duì)象绑改。
const express = require('express')
const bodyParser = require('body-parser')
const router = express.Router()
router.all('/body-parser/true', bodyParser.json(), (req, res) => {
? ? res.send(req.body)
})
router.all('/body-parser/false', (req, res) => {
? ? res.send(req.body)
})
module.exports = router
express 4.x默認(rèn)的req.query就是一個(gè)對(duì)象,因此不需要對(duì)查詢字符串進(jìn)行轉(zhuǎn)換兄一。
3. 靜態(tài)資源中間件
express提供了express.static()作為靜態(tài)資源中間件使用厘线,只需要傳遞一個(gè)靜態(tài)資源路徑即可。
在項(xiàng)目目錄中加入一個(gè)public文件夾出革,放入一個(gè)nodejs.jpg文件皆的。
編寫如下代碼。
app.use(express.static(path.resolve(__dirname, './public')))
在瀏覽器直接輸入網(wǎng)站根路徑+文件名即可訪問文件蹋盆。
4.4 Express 腳手架
使用express-generator可以快速搭建一個(gè)Express項(xiàng)目,并能自動(dòng)下載依賴硝全,可以省去很多步驟栖雾。
使用npx一鍵安裝
npx express-generator --ejs <項(xiàng)目名稱>
npx命令
npx是npm從5.2版開始增加了的命令,主要用于快速調(diào)用node_modules/.bin/ 的命令伟众,如:
以前:$ node-modules/.bin/mocha --version
現(xiàn)在:$ npx mocha --version
同時(shí)還能避免全局安裝模塊而直接使用這種全局模塊析藕,如:create-react-app模塊
以前:
1.先安裝:npm install -g create-react-app;
2.在使用:create-react-app 工程名凳厢;
現(xiàn)在一步搞定:
npx create-react-app 工程名
express-generator 支持的可選參數(shù)
Options:
? ? -h, --help? ? ? ? ? 輸出使用方法
? ? ? ? --version? ? ? 輸出版本號(hào)
? ? -e, --ejs? ? ? ? ? 添加對(duì) ejs 模板引擎的支持
? ? ? ? --hbs? ? ? ? ? 添加對(duì) handlebars 模板引擎的支持
? ? ? ? --pug? ? ? ? ? 添加對(duì) pug 模板引擎的支持
? ? -H, --hogan? ? ? ? 添加對(duì) hogan.js 模板引擎的支持
? ? ? ? --no-view? ? ? 創(chuàng)建不帶視圖引擎的項(xiàng)目
? ? -v, --view <engine> 添加對(duì)視圖引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默認(rèn)是 jade 模板引擎)
? ? -c, --css <engine>? 添加樣式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默認(rèn)是普通的 css 文件)
? ? ? ? --git? ? ? ? ? 添加 .gitignore
? ? -f, --force? ? ? ? 強(qiáng)制在非空目錄下創(chuàng)建
模板引擎
Express模板引擎(Template Engine), 是用來(lái)解析對(duì)應(yīng)類型模板文件然后動(dòng)態(tài)生成由數(shù)據(jù)和靜態(tài)頁(yè)面組成的HTML的一個(gè)工具账胧,也就是可以編譯成HTML文件的一種預(yù)編譯文件。
Express中最常用的兩個(gè)模板工具是ejs和jade(已經(jīng)改名為pug先紫,不過習(xí)慣上還是叫jade)治泥,ejs是非常接近html語(yǔ)法的模板,而jade模板是非常簡(jiǎn)潔的語(yǔ)法遮精,和HTML語(yǔ)法差異較大居夹,jade模板在這里可以學(xué)習(xí)。
簡(jiǎn)要學(xué)習(xí)ejs模板語(yǔ)法:官方文檔
<!DOCTYPE html>
<html>
<head>
? <title><%= title %></title>
? <link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
? <%# 渲染變量 %>
? <h1><%= title %></h1>
? <p>Welcome to <%= title %></p>
? <% var a = 10, b = 11; %>
? <% if(a > b){ %>
? <div>ddddd</div>
? <% } %>
? <ul>
? ? <%# 只執(zhí)行代碼,不渲染內(nèi)容 %>
? ? <% users.forEach(function(user){ %>
? ? <%# 渲染變量 %>
? ? <li><%= user.name %></li>
? ? <% }) %>
? </ul>
</body>
</html>
? 標(biāo)簽含義:
? ```markdown
? `<%` '腳本' 標(biāo)簽本冲,用于流程控制准脂,無(wú)輸出。
? `<%_` 刪除其前面的空格符
? `<%=` 輸出數(shù)據(jù)到模板(輸出是轉(zhuǎn)義 HTML 標(biāo)簽)
? `<%-` 輸出非轉(zhuǎn)義的數(shù)據(jù)到模板
? `<%#` 注釋標(biāo)簽檬洞,不執(zhí)行狸膏、不輸出內(nèi)容
? `<%%` 輸出字符串 '<%'
`%>` 一般結(jié)束標(biāo)簽
? `-%>` 刪除緊隨其后的換行符
`_%>` 將結(jié)束標(biāo)簽后面的空格符刪除
? 模板引擎和索取模板的目錄,需要通過以下代碼指定:
? app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
? 模板是在路由中通過res.render渲染并輸出的:
? router.get('/', function (req, res, next) {
? ? res.render('index', { title: 'Express', users: [{ name: '花花' }, { name: '世界' }] });
? });
五. 使用MongoDB數(shù)據(jù)庫(kù)
到目前為止添怔,我們開發(fā)的API接口都是生成的假數(shù)據(jù)湾戳。如果有這樣一個(gè)系統(tǒng)贤旷,需要使用Express+Bootstrap開發(fā)一套用戶的管理系統(tǒng),所有用戶的數(shù)據(jù)通過上傳來(lái)提供院塞,并且需要把數(shù)據(jù)保存遮晚。那么這種情形下,數(shù)據(jù)庫(kù)就成了必不可少的工具拦止。
5.1 什么是數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)指的是以一定方式儲(chǔ)存在一起县遣、能為多個(gè)用戶共享、具有盡可能小的冗余度汹族、與應(yīng)用程序彼此獨(dú)立的數(shù)據(jù)集合萧求,用戶可以對(duì)文件中的數(shù)據(jù)運(yùn)行新增、截取顶瞒、更新夸政、刪除等操作。
數(shù)據(jù)庫(kù)軟件應(yīng)稱為DBMS(數(shù)據(jù)庫(kù)管理系統(tǒng))榴徐。數(shù)據(jù)庫(kù)是通過 DBMS 創(chuàng)建和操縱的容器守问。數(shù)據(jù)庫(kù)可以是保存在硬件設(shè)備上的文件,但也可以不是坑资。在很大程度上說(shuō)耗帕,數(shù)據(jù)庫(kù)究竟是文件還是別的什么東西并不重要,因?yàn)槟悴⒉恢苯釉L問數(shù)據(jù)庫(kù)袱贮;你使用的是DBMS仿便,它替你訪問數(shù)據(jù)庫(kù)。
5.2 數(shù)據(jù)庫(kù)的分類
按照邏輯劃分攒巍,數(shù)據(jù)庫(kù)分為關(guān)系型和非關(guān)系型數(shù)據(jù)庫(kù)嗽仪。
關(guān)系型數(shù)據(jù)庫(kù)
關(guān)系型數(shù)據(jù)庫(kù)是創(chuàng)建在關(guān)系模型基礎(chǔ)上的數(shù)據(jù)庫(kù),它是數(shù)據(jù)存儲(chǔ)的傳統(tǒng)標(biāo)準(zhǔn)柒莉。標(biāo)準(zhǔn)數(shù)據(jù)查詢語(yǔ)言SQL就是一種基于關(guān)系數(shù)據(jù)庫(kù)的語(yǔ)言闻坚,這種語(yǔ)言執(zhí)行對(duì)關(guān)系數(shù)據(jù)庫(kù)中數(shù)據(jù)的檢索和操作。
關(guān)系數(shù)據(jù)庫(kù)使用表存儲(chǔ)數(shù)據(jù)常柄,在使用之前需要定義數(shù)據(jù)結(jié)構(gòu)鲤氢,而且具有數(shù)據(jù)完整性約束。
SQL是精確的西潘。它最適合于具有精確標(biāo)準(zhǔn)的定義明確的項(xiàng)目卷玉。典型的使用場(chǎng)景是在線商店和銀行系統(tǒng)。
常用的關(guān)系數(shù)據(jù)庫(kù):
MySQL
PostgreSQL
SQL Server
Oracle
非關(guān)系型數(shù)據(jù)庫(kù)(NoSQL)
非關(guān)系型數(shù)據(jù)庫(kù)是基于鍵值對(duì)的喷市,可以想象成表中的主鍵和值的對(duì)應(yīng)關(guān)系相种,而且不需要經(jīng)過SQL層的解析,所以性能非常高,而且易于擴(kuò)展寝并。
菲關(guān)系型數(shù)據(jù)庫(kù)使用類JSON的文檔存儲(chǔ)數(shù)據(jù)箫措,格式不限定,不會(huì)對(duì)數(shù)據(jù)進(jìn)行嚴(yán)格驗(yàn)證衬潦。
NoSQL是多變的斤蔓。它最適合于具有不確定需求的數(shù)據(jù)。典型的使用場(chǎng)景是社交網(wǎng)絡(luò)镀岛,客戶管理和網(wǎng)絡(luò)分析系統(tǒng)弦牡。
Redis
MongoDB
關(guān)系型和非關(guān)系型數(shù)據(jù)庫(kù)無(wú)分誰(shuí)優(yōu)誰(shuí)劣,他們有各自應(yīng)用的場(chǎng)景漂羊,而且很多情況還會(huì)結(jié)合使用驾锰。
5.3 MongoDB數(shù)據(jù)庫(kù)
MongoDB 是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù)。由 C++ 語(yǔ)言編寫走越。旨在為 WEB 應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案椭豫。
MongoDB并非純粹的非關(guān)系型數(shù)據(jù)庫(kù), 是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品旨指,是非關(guān)系數(shù)據(jù)庫(kù)當(dāng)中功能最豐富赏酥,最像關(guān)系數(shù)據(jù)庫(kù)的。MongoDB 將數(shù)據(jù)存儲(chǔ)為一個(gè)文檔谆构,數(shù)據(jù)結(jié)構(gòu)由鍵值(key=>value)對(duì)組成今缚。MongoDB 文檔類似于 JSON 對(duì)象。字段值可以包含其他文檔低淡,數(shù)組及文檔數(shù)組。
因?yàn)镸ongoDB是基于JSON的查詢和存儲(chǔ)瞬项,它最接近JavaScript蔗蹋,而且性能很好,因此我們選用他來(lái)作為Express的數(shù)據(jù)庫(kù)使用囱淋。
5.3.1 安裝MongoDB
Windows猪杭、Mac安裝官網(wǎng)https://www.mongodb.com/download-center/enterprise
數(shù)據(jù)庫(kù)安裝過程記得選擇順帶安裝TLS/SSL工具。
5.3.2 準(zhǔn)備工作
安裝完畢后妥衣,我們需要?jiǎng)?chuàng)建一個(gè)用來(lái)存儲(chǔ)數(shù)據(jù)的目錄皂吮。
windows用戶需要手動(dòng)在C:\盤目錄創(chuàng)建一個(gè)data目錄,然后data內(nèi)部創(chuàng)建一個(gè)db目錄税手。
Mac用戶需要在root根目錄下創(chuàng)建一個(gè)data目錄蜂筹,然后data內(nèi)部創(chuàng)建一個(gè)db目錄。
啟動(dòng)數(shù)據(jù)庫(kù):
mongod
啟動(dòng)成功后芦倒,保留這個(gè)終端窗口艺挪,開啟一個(gè)新的窗口,輸入mongo進(jìn)入mongo shell模式兵扬。
mongo
Windows用戶如果無(wú)法使用命令麻裳,需要設(shè)置環(huán)境變量指向MongoDB安裝目錄的bin目錄口蝠。
5.3.3 MongoDB中的概念
MongoDB是非關(guān)系型數(shù)據(jù)庫(kù),它其中有些術(shù)語(yǔ)相對(duì)于關(guān)系型數(shù)據(jù)庫(kù)是不一樣的津坑。
MongoDB術(shù)語(yǔ)對(duì)應(yīng)的SQL術(shù)語(yǔ)解釋/說(shuō)明
databasedatabase數(shù)據(jù)庫(kù)
collectiontable數(shù)據(jù)庫(kù)表/集合
documentrow數(shù)據(jù)記錄行/文檔
fieldcolumn數(shù)據(jù)字段/域
indexindex索引
table joins表連接,MongoDB不支持
primary keyprimary key主鍵,MongoDB自動(dòng)將_id字段設(shè)置為主鍵
數(shù)據(jù)庫(kù)(Database)
一個(gè)mongodb中可以建立多個(gè)數(shù)據(jù)庫(kù)妙蔗。
MongoDB的默認(rèn)數(shù)據(jù)庫(kù)為"db",該數(shù)據(jù)庫(kù)存儲(chǔ)在data目錄中疆瑰。
MongoDB的單個(gè)實(shí)例可以容納多個(gè)獨(dú)立的數(shù)據(jù)庫(kù)眉反,每一個(gè)都有自己的集合和權(quán)限,不同的數(shù)據(jù)庫(kù)也放置在不同的文件中乃摹。
show dbs 命令可以顯示所有數(shù)據(jù)的列表禁漓。
> show dbs
執(zhí)行db命令可以顯示當(dāng)前數(shù)據(jù)庫(kù)對(duì)象或集合。
> db
運(yùn)行use命令孵睬,可以連接到一個(gè)指定的數(shù)據(jù)庫(kù)播歼。
> use local
文檔(Document)
文檔是一組鍵值(key-value)對(duì)。MongoDB 的文檔內(nèi)部的字段和數(shù)據(jù)類型并不是強(qiáng)制性的掰读,這與關(guān)系型數(shù)據(jù)庫(kù)有很大的區(qū)別秘狞,也是 MongoDB 非常突出的特點(diǎn)。
需要注意的是:
文檔中的鍵/值對(duì)是有序的蹈集。
文檔中的值不僅可以是在雙引號(hào)里面的字符串烁试,還可以是其他幾種數(shù)據(jù)類型(甚至可以是整個(gè)嵌入的文檔)。
MongoDB區(qū)分類型和大小寫拢肆。
MongoDB的文檔不能有重復(fù)的鍵减响。
db.col.findOne()
集合(collection)
多個(gè)文檔可以構(gòu)成一個(gè)集合。
集合支持capped特性郭怪,該特性會(huì)創(chuàng)建一個(gè)固定大小的集合支示,這樣collection 的數(shù)據(jù)存儲(chǔ)空間值是提前分配的。
db.createCollection("mycoll", {capped:true, size:100000})
數(shù)據(jù)類型
ObjectId
MongoDB支持很多種數(shù)據(jù)類型鄙才,但有一種類型很重要也很特殊颂鸿,就是ObjectId類型。
ObjectId 類似主鍵攒庵,可以很快的去生成和排序嘴纺,它由12 bytes組成。
MongoDB 中存儲(chǔ)的文檔必須有一個(gè) _id 鍵浓冒,這個(gè)鍵的值默認(rèn)是個(gè) ObjectId 對(duì)象栽渴。
由于 ObjectId 中保存了創(chuàng)建的時(shí)間戳,所以你不需要為你的文檔保存時(shí)間戳字段稳懒,你可以通過getTimestamp 函數(shù)來(lái)獲取文檔的創(chuàng)建時(shí)間:
objectId.getTimestamp()
字符串
字符串默認(rèn)UTF-8編碼熔萧。
日期
表示當(dāng)前距離 1970年1月1日 的毫秒數(shù)。日期類型是有符號(hào)的, 負(fù)數(shù)表示 1970 年之前的日期。
5.3.4 shell操作數(shù)據(jù)庫(kù)
MongoDB 中默認(rèn)的數(shù)據(jù)庫(kù)為 test佛致,如果你沒有創(chuàng)建新的數(shù)據(jù)庫(kù)贮缕,集合將存放在 test 數(shù)據(jù)庫(kù)中。
創(chuàng)建數(shù)據(jù)庫(kù)
> use runoob
switched to db runoob
> db
runoob
>
查看數(shù)據(jù)庫(kù)
> show dbs
admin? 0.000GB
config? 0.000GB
local? 0.000GB
>
剛剛創(chuàng)建的數(shù)據(jù)庫(kù)沒有展示出來(lái)俺榆,因?yàn)樗€沒有添加數(shù)據(jù)感昼。
> db.runoob.insert({"name":"菜鳥教程"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin? 0.000GB
config? 0.000GB
local? 0.000GB
runoob? 0.000GB
刪除數(shù)據(jù)庫(kù)
> use runoob
switched to db runoob
> db.dropDatabase()
{ "dropped" : "runoob", "ok" : 1 }
創(chuàng)建集合
> db.createCollection("users")
{ "ok" : 1 }
>
查看集合
> show collections
users
system.indexes
刪除集合
> db.users.drop()
集合中插入文檔
>db.users.insert({"name":"小明"})
集合中更新文檔
更新的命令比較復(fù)雜:
db.collection.update(
? <query>,
? <update>,
? {
? ? upsert: <boolean>,
? ? multi: <boolean>,
? ? writeConcern: <document>
? }
)
參數(shù)說(shuō)明:
query?: update的查詢條件,類似sql update查詢內(nèi)where后面的罐脊。
update?: update的對(duì)象和一些更新的操作符(如$,$inc...)等定嗓,也可以理解為sql update查詢內(nèi)set后面的
upsert?: 可選,這個(gè)參數(shù)的意思是萍桌,如果不存在update的記錄宵溅,是否插入objNew,true為插入,默認(rèn)是false上炎,不插入恃逻。
multi?: 可選,mongodb 默認(rèn)是false,只更新找到的第一條記錄藕施,如果這個(gè)參數(shù)為true,就把按條件查出來(lái)多條記錄全部更新寇损。
writeConcern?:可選,拋出異常的級(jí)別裳食。
> db.users.update({'name':'小明'},{$set:{'name':'小花'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })? # 輸出信息
刪除文檔
db.collection.remove(
? <query>,
? {
? ? justOne: <boolean>,
? ? writeConcern: <document>
? }
)
參數(shù)說(shuō)明:
query?:(可選)刪除的文檔的條件矛市。
justOne?: (可選)如果設(shè)為 true 或 1,則只刪除一個(gè)文檔诲祸,如果不設(shè)置該參數(shù)浊吏,或使用默認(rèn)值 false,則刪除所有匹配條件的文檔救氯。
writeConcern?:(可選)拋出異常的級(jí)別卿捎。
> db.col.remove({'title':'MongoDB 教程'})
WriteResult({ "nRemoved" : 2 })
查詢文檔
db.collection.find(query, projection)
query?:可選,使用查詢操作符指定查詢條件
projection?:可選径密,使用投影操作符指定返回的鍵。查詢時(shí)返回文檔中所有鍵值躺孝, 只需省略該參數(shù)即可(默認(rèn)省略)享扔。
> db.col.find().pretty()
{
? ? ? ? "_id" : ObjectId("56063f17ade2f21f36b03133"),
? ? ? ? "title" : "MongoDB 教程",
? ? ? ? "description" : "MongoDB 是一個(gè) Nosql 數(shù)據(jù)庫(kù)",
? ? ? ? "by" : "菜鳥教程",
? ? ? ? "url" : "http://www.runoob.com",
? ? ? ? "tags" : [
? ? ? ? ? ? ? ? "mongodb",
? ? ? ? ? ? ? ? "database",
? ? ? ? ? ? ? ? "NoSQL"
? ? ? ? ],
? ? ? ? "likes" : 100
}
此外findOne可以只查詢一個(gè)
上面的查詢是 基于AND條件,也可以基于OR條件查詢
>db.col.find({$or:[{"by":"菜鳥教程"},{"title": "MongoDB 教程"}]}).pretty()
{
? ? ? ? "_id" : ObjectId("56063f17ade2f21f36b03133"),
? ? ? ? "title" : "MongoDB 教程",
? ? ? ? "description" : "MongoDB 是一個(gè) Nosql 數(shù)據(jù)庫(kù)",
? ? ? ? "by" : "菜鳥教程",
? ? ? ? "url" : "http://www.runoob.com",
? ? ? ? "tags" : [
? ? ? ? ? ? ? ? "mongodb",
? ? ? ? ? ? ? ? "database",
? ? ? ? ? ? ? ? "NoSQL"
? ? ? ? ],
? ? ? ? "likes" : 100
}
>
此外還可以基于大于植袍、小于的查詢
> db.col.find({"by":"小明", "likes": {$gt:50}, $or: [{"by": "菜鳥教程"},{"title": "MongoDB 教程"}]}).pretty()
{
? ? ? ? "_id" : ObjectId("56063f17ade2f21f36b03133"),
? ? ? ? "title" : "MongoDB 教程",
? ? ? ? "description" : "MongoDB 是一個(gè) Nosql 數(shù)據(jù)庫(kù)",
? ? ? ? "by" : "菜鳥教程",
? ? ? ? "url" : "http://www.runoob.com",
? ? ? ? "tags" : [
? ? ? ? ? ? ? ? "mongodb",
? ? ? ? ? ? ? ? "database",
? ? ? ? ? ? ? ? "NoSQL"
? ? ? ? ],
? ? ? ? "likes" : 100
}
操作格式范例RDBMS中的類似語(yǔ)句
等于{:}db.col.find({"by":"菜鳥教程"}).pretty()where by = '菜鳥教程'
小于{:{$lt:}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小于或等于{:{$lte:}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大于{:{$gt:}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大于或等于{:{$gte:}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等于{:{$ne:}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50
limit方法
如果你需要在MongoDB中讀取指定數(shù)量的數(shù)據(jù)記錄惧眠,可以使用MongoDB的Limit方法,limit()方法接受一個(gè)數(shù)字參數(shù)于个,該參數(shù)指定從MongoDB中讀取的記錄條數(shù)氛魁。
> db.col.find({},{"title":1,_id:0}).limit(2)
{ "title" : "PHP 教程" }
{ "title" : "Java 教程" }
我們除了可以使用limit()方法來(lái)讀取指定數(shù)量的數(shù)據(jù)外,還可以使用skip()方法來(lái)跳過指定數(shù)量的數(shù)據(jù),skip方法同樣接受一個(gè)數(shù)字參數(shù)作為跳過的記錄條數(shù)秀存。
以下實(shí)例只會(huì)顯示第二條文檔數(shù)據(jù)
>db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
{ "title" : "Java 教程" }
>
排序
在 MongoDB 中使用 sort() 方法對(duì)數(shù)據(jù)進(jìn)行排序捶码,sort() 方法可以通過參數(shù)指定排序的字段,并使用 1 和 -1 來(lái)指定排序的方式或链,其中 1 為升序排列惫恼,而 -1 是用于降序排列。
>db.col.find({},{"title":1,_id:0}).sort({"likes":-1})
{ "title" : "PHP 教程" }
{ "title" : "Java 教程" }
{ "title" : "MongoDB 教程" }
>
索引
索引通常能夠極大的提高查詢的效率澳盐,如果沒有索引祈纯,MongoDB在讀取數(shù)據(jù)時(shí)必須掃描集合中的每個(gè)文件并選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是非常低的叼耙,特別在處理大量的數(shù)據(jù)時(shí)腕窥,查詢可以要花費(fèi)幾十秒甚至幾分鐘,這對(duì)網(wǎng)站的性能是非常致命的筛婉。
為col集合建立索引簇爆,基于title
>db.col.createIndex({"title":1})
>
聚合
MongoDB中聚合(aggregate)主要用于處理數(shù)據(jù)(諸如統(tǒng)計(jì)平均值,求和等),并返回計(jì)算后的數(shù)據(jù)結(jié)果倾贰。
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
? "result" : [
? ? ? {
? ? ? ? "_id" : "runoob.com",
? ? ? ? "num_tutorial" : 2
? ? ? },
? ? ? {
? ? ? ? "_id" : "Neo4j",
? ? ? ? "num_tutorial" : 1
? ? ? }
? ],
? "ok" : 1
}
>
表達(dá)式描述實(shí)例
$sum計(jì)算總和冕碟。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg計(jì)算平均值db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min獲取集合中所有文檔對(duì)應(yīng)值得最小值。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max獲取集合中所有文檔對(duì)應(yīng)值得最大值匆浙。db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push在結(jié)果文檔中插入值到一個(gè)數(shù)組中安寺。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet在結(jié)果文檔中插入值到一個(gè)數(shù)組中,但不創(chuàng)建副本首尼。db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first根據(jù)資源文檔的排序獲取第一個(gè)文檔數(shù)據(jù)挑庶。db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last根據(jù)資源文檔的排序獲取最后一個(gè)文檔數(shù)據(jù)db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])
以上就是MongoDB的基本使用方式,我們?cè)诼?lián)系過程中發(fā)現(xiàn)软能,mongoDB的shell非常難用迎捺,在這里推薦使用GUI工具來(lái)管理數(shù)據(jù)庫(kù):Robo3T來(lái)管理數(shù)據(jù)庫(kù)。