NodeJS入門(mén)從這篇文章開(kāi)始

NodeJs簡(jiǎn)介

V8引擎本身就是用于chrome瀏覽器的JS部分,但是Ryan Dahe 這哥們,鬼才般的,把這個(gè)V8搬到了服務(wù)器上用于服務(wù)器的軟件。是一個(gè)專注實(shí)現(xiàn)高性能Web 服務(wù)器優(yōu)化的專家,幾經(jīng)探索,幾經(jīng)挫折后,遇到V8而誕生的項(xiàng)目。

Node.js是一個(gè)讓JavaScript運(yùn)行在服務(wù)器端的開(kāi)發(fā)平臺(tái),它讓所有JavaScript的觸角延伸到了服務(wù)器,可以與PHP、Python、 Ruby 平起平坐。

Node 似乎有些不同:

  • Node.js不是一種獨(dú)立的語(yǔ)言,與 PHP Python Ruby的“基是語(yǔ)言也是平臺(tái)”不同, Node.js的使用是JavaScript進(jìn)行編程,運(yùn)行在JavaScript引擎上(V8)。

  • PHP JSP等相比, Node.js跳過(guò)了Apache Nginx IISHTTP 服務(wù)器,他自己不用建設(shè)在任何服務(wù)器軟件之上。Node.js的許多設(shè)計(jì)理念與經(jīng)典架構(gòu)(LAMP)有著很大的不同,可以提供強(qiáng)大的伸縮能力。

Node.js自身哲學(xué),是花最小的硬件成本,最求更高的并發(fā),更高的處理性能。

NodeJS官網(wǎng) Node.js? is a JavaScript runtime built on Chrome's V8 JavaScript engine.

Node.js的特點(diǎn)

單線程

Java PHP或者.Net等服務(wù)器語(yǔ)言中,會(huì)為每一個(gè)客戶端鏈接創(chuàng)建一個(gè)新的線程。而每個(gè)線程需要消耗大約2MB內(nèi)存。也就是說(shuō),理論上,一個(gè)8GB內(nèi)存的服務(wù)器可以同時(shí)連接的最大用戶數(shù)為4000個(gè)左右。要讓Web應(yīng)用程序支持更多的用戶,就需要增加服務(wù)器的數(shù)量,而Web應(yīng)用程序的硬件成本當(dāng)然就上升了。

Node.js不為每個(gè)客戶鏈接創(chuàng)建一個(gè)新的線程,而僅僅使用一個(gè)線程。當(dāng)有用戶連接了,就出發(fā)一個(gè)內(nèi)部事件,通過(guò)非阻塞 I/O 、事件驅(qū)動(dòng)機(jī)制,讓Node.js程序宏觀上也是并行的。使用Node.js,一個(gè)8GB內(nèi)存的服務(wù)器可以同時(shí)處理超過(guò)4萬(wàn)用戶的連接。

另外,單線程帶來(lái)的好處,還有操作系統(tǒng)不再有線程創(chuàng)建、銷毀的事件開(kāi)銷。

壞處,一個(gè)用戶造成了線程的崩潰,整個(gè)服務(wù)都崩潰了。


非阻塞I/O

例如,當(dāng)在訪問(wèn)數(shù)據(jù)庫(kù)取得數(shù)據(jù)的時(shí)候,需要一段時(shí)間。在傳統(tǒng)的單線程處理機(jī)制中,在執(zhí)行了訪問(wèn)數(shù)據(jù)庫(kù)代碼之后,整個(gè)線程豆?jié){暫停下來(lái),等待數(shù)據(jù)庫(kù)返回結(jié)構(gòu),才能執(zhí)行后面的代碼。也就是說(shuō),<font color="red">I/O 阻塞了代碼的執(zhí)行,極大地降低了程序執(zhí)行速率。</font>

由于Node.js中采用了非阻塞性 I/O 機(jī)制,因此在執(zhí)行了訪問(wèn)數(shù)據(jù)庫(kù)的代碼之后,將立即轉(zhuǎn)而執(zhí)行其后面的代碼,把數(shù)據(jù)庫(kù)返回結(jié)果的處理代碼放在回調(diào)函數(shù)中,從而提高了程序的執(zhí)行效率。

當(dāng)某個(gè) I/O 執(zhí)行完畢時(shí),將以事件的形式通知 I/O 操作的線程,線程執(zhí)行這個(gè)事件的回調(diào)函數(shù)。為了處理異步 I/O,線程必須有事件循環(huán),不斷檢查有沒(méi)有未處理的事件,依次予以處理。

事件驅(qū)動(dòng)

Node中,客戶端請(qǐng)求建立連接,提交數(shù)據(jù)等行為,會(huì)觸發(fā)相應(yīng)的事件。在Node中,在一個(gè)時(shí)刻,只能執(zhí)行一個(gè)事件回調(diào)函數(shù),但是在執(zhí)行一個(gè)事件回調(diào)函數(shù)的中途,可以轉(zhuǎn)而處理其他事件(比如,又有新用戶連接了),然后返回執(zhí)行原事件的回調(diào)函數(shù),這種事件機(jī)制,稱為“事件環(huán)”事件。


說(shuō)是三個(gè)特點(diǎn),實(shí)際上時(shí)一個(gè)特點(diǎn),離開(kāi)誰(shuí)都不行,都玩不轉(zhuǎn)了。
Node.js很像摳門(mén)的餐廳老板,只聘請(qǐng)一個(gè)服務(wù)員,服務(wù)很多人。結(jié)果比很多服務(wù)員效率還高。
Node.js中所有 I/O 都是異步的,回調(diào)函數(shù)套回調(diào)函數(shù)。

適合開(kāi)發(fā)什么?

Node.js 適合用來(lái)開(kāi)發(fā)什么樣的應(yīng)用程序呢?

善于 I/O, 不善于計(jì)算。因?yàn)?code>Node.js最擅長(zhǎng)就是任務(wù)調(diào)度,如果你的任務(wù)有很多的 CPU 計(jì)算,實(shí)際上是這個(gè)計(jì)算阻塞了這個(gè)單線程,就不適合 Node 開(kāi)發(fā)。

當(dāng)應(yīng)用程序需要處理大量并發(fā)的 I/O, 而在向客戶端發(fā)出響應(yīng)之前,應(yīng)用程序內(nèi)部并不需要進(jìn)行非常復(fù)雜的處理的時(shí)候,Node.js非常合適。Node.js也非常適合與 web socket配合,開(kāi)發(fā)長(zhǎng)連接的實(shí)時(shí)交互應(yīng)用程序。

比如

  • 用戶表單收集

  • 考試系統(tǒng)

  • 聊天室

  • 圖文直播

  • 提供 JSONAPI

Node.js 不是銀彈

Node.js 無(wú)法挑戰(zhàn)老牌的后臺(tái)語(yǔ)言

Node.js 本身就是極客追求性能極致的產(chǎn)物,缺少了很多服務(wù)器的健壯考量。所以 Node 不可能應(yīng)用在銀行、證券、電信等需要極高可靠性的業(yè)務(wù)當(dāng)中。

一線企業(yè)中,Node是怎么用的?拿來(lái)做什么?怎么做?

哪些公司在用nodejs?

Node不是銀彈,只是你工具箱中的一個(gè)小工具

NodeJs安裝及配置

Node.js安裝及環(huán)境配置 For Windows

Node.js安裝及環(huán)境配置 For Mac

NodeJs 沒(méi)有Web容器的概念

NodeJs頂層路由設(shè)計(jì),Url和物理文件是沒(méi)有關(guān)系的

NodeJs沒(méi)有 Web 容器的概念所以無(wú)法搜尋靜態(tài)資源

NodeJs模塊

NodeJs中,將很多功能劃分成了一個(gè)個(gè) mudule,類似于與Java中包的概念,程序中會(huì)用到一些模塊,有一些不用,所以為了效率,你用什么,就 require 什么。

Http 模塊

http文檔

該模塊中創(chuàng)建 server 時(shí),回調(diào)參數(shù)中會(huì)接受 resreq 兩個(gè)參數(shù)。

req 中最關(guān)鍵的就是 req.url 屬性,表示用戶請(qǐng)求的 URL 地址。所有的路由設(shè)計(jì),都是通過(guò) req.url 來(lái)實(shí)現(xiàn)的。

我們比較關(guān)心的不是拿到 URL,而是識(shí)別這個(gè) URL。

識(shí)別 URL,用到兩個(gè)新模塊,第一個(gè)就是 url 模塊,第二個(gè)就是 querystring 模塊。

url模塊

url文檔

url.parse() //解析 URL (http://nodejs.cn/api/http.html#http_message_url)

querystring 模塊

querystring 文檔

querystring.stringify(obj[, sep[, eq[, options]]])

CommonJS 和 NodeJs模塊、自定義模塊

什么是CommonJS

JavaScript是一個(gè)強(qiáng)大的面相對(duì)象的語(yǔ)言。他有很多快速高效的解釋器。然而,JavaScript標(biāo)準(zhǔn)定義的 API 是為了構(gòu)建基于瀏覽器的應(yīng)用程序。并沒(méi)有制定一個(gè)用于更廣泛的應(yīng)用程序的標(biāo)準(zhǔn)。CommonJS 規(guī)范的提出,主要是為了彌補(bǔ)當(dāng)前 JavaScript沒(méi)有標(biāo)準(zhǔn)庫(kù)的缺陷。它的終極目標(biāo)就是:提供一個(gè)類似 Python,RubyJava語(yǔ)言的標(biāo)準(zhǔn)庫(kù),而不只是讓JavaScipt停留在小腳本程序的階段。用 CommonJS API編寫(xiě)出的應(yīng)用,不僅可以利用JavaScript開(kāi)發(fā)客戶端應(yīng)用,而且還可以編寫(xiě)以下應(yīng)用。

  • 服務(wù)端 JavaScript 應(yīng)用程序 (Nodejs)

  • 命令行工具

  • 桌面圖像界面應(yīng)用程序

CommonJS 就是模塊化的標(biāo)準(zhǔn), nodejs就是 CommonJS(模塊化)的實(shí)現(xiàn)

CommonJS簡(jiǎn)介

Nodejs中模塊化

Node應(yīng)用由模塊組成,采用 CommonJS 模塊規(guī)范

Node中,模塊分為兩類:一類是 核心模塊;另一類是用戶編寫(xiě)的模塊,稱為 文件模塊。

  • 核心模塊部分在 Node 源碼的編譯過(guò)程中,編譯進(jìn)了二進(jìn)制執(zhí)行文件。在 Node進(jìn)程啟動(dòng)時(shí),部分核心模塊就被直接加載進(jìn)內(nèi)存中,所以這部分核心模塊引入時(shí),文件定位和編譯執(zhí)行這兩個(gè)步驟可以省略掉,并且在路徑分析中優(yōu)先判斷,所以它的加載速度時(shí)最快的。 如:HTTP模塊、URL模塊、FS模塊都是 node 內(nèi)置的核心模塊,可以直接引入使用
  • 文件模塊則是在運(yùn)行時(shí)動(dòng)態(tài)加載,需要完成的路徑分析,文件定位,編譯執(zhí)行過(guò)程,速度相比核心模塊稍微慢一些,但是用的非常多。這些模塊需要我們自己定義。

CommonJS(Nodejs)中自定義模塊的規(guī)定

  1. 我們可以把公共的抽離成為一個(gè)單獨(dú)的 js 文件作為一個(gè)模塊,默認(rèn)情況下面這個(gè)模塊里面的方法或者屬性,外面是沒(méi)法訪問(wèn)的。如果要讓外部可以訪問(wèn)模塊里面的方法或者屬性,就必須在模塊里面通過(guò) exports 或者 module.exports 暴露屬性或者方法。
  2. 在需要使用這些模塊的文件中,通過(guò) require 的方式引入這個(gè)模塊。這個(gè)時(shí)候可以使用模塊里面暴露的屬性和方法。

Nodejs 中包、npm、第三方模塊、package.json的使用

Nodejs中處理它自己提供的核心模塊外,我們可以 自己定義模塊,也可以使用 第三方的模塊。 Nodejs中第三方模塊由包組成,可以通過(guò) 來(lái)對(duì)一組具有相互依賴關(guān)系的模塊進(jìn)行統(tǒng)一管理。

完全符合CommnonJS規(guī)范的的<font color=red>包目錄</font>一般包含如下文件

  • package.json 包描述文件
  • bin: 用于存放可執(zhí)行二進(jìn)制的目錄
  • Lib: 用于存放 JavaScript 代碼的目錄
  • Doc: 用于存放文檔的目錄

NPM概述及使用簡(jiǎn)介

Yarn使用簡(jiǎn)介

NodeJS Fs模塊

文件系統(tǒng)API

/*
* 1. fs.stat  檢測(cè)是文件還是目錄
* 2. fs.mkdir 創(chuàng)建目錄
* 3. fs.writeFile 創(chuàng)建寫(xiě)入文件
* 4. fs.appendFile 追加文件
* 5. fs.readFile 讀取文件
* 6. fs.rename 重命名文件
* 7. fs.readdir 讀取目錄
* 8. fs.rmdir 刪除目錄
* 9. fs.unlink 刪除文件
* 10. fs.createReadStream 一步讀取文件
* 11. fs.createWriteStream 一步寫(xiě)入文件
* 管道形式寫(xiě)入
* */

Path 模塊

Path 模塊API

Nodejs 的非阻塞 I/O,異步,事件驅(qū)動(dòng)

Nodejs中大部分方法都是異步的, Nodejs有很多內(nèi)置事件,我們可以通過(guò)引入 events 模塊,并通過(guò)實(shí)例化 EventEmmitter 類來(lái)綁定和監(jiān)聽(tīng)事件。

可以在異步事件中添加回調(diào)函數(shù)來(lái)獲取異步數(shù)據(jù)。

EJS 模板渲染 (一種保持前后端分離的后端數(shù)據(jù)渲染)

EJS模板API文檔

ejs.renderFile(filename,data,option,function(err,str){});

布局相關(guān)(Layouts)

Express 路由模塊的封裝

const url = require('url');

/* 封裝改變r(jià)es, 綁定res.send */
function changeRes(res){
    res.send = function (data) {
        res.writeHead(200, {'Content-Type':'text/html;charset="utf8"'});
        res.end(data);
    }
}

/* 暴露的模塊 */
const Serve = function () {
    let G = this;
    /* 處理get和post請(qǐng)求 */
    this._get = {};
    this._post = {};

    let app = function (req,res) {
        changeRes(res);
        /* 獲取路由 */
        let pathname = url.parse(req.url).pathname;
        if(!pathname.endsWith('/')){
            pathname = pathname + '/';
        }

        /* 獲取 get post 請(qǐng)求 */
        let method = req.method.toLowerCase();
        if(G['_'+method][pathname]){
            if(method === 'post'){
                let strPost = '';
                req.on('data',function (chunk) {
                    strPost += chunk;
                });
                req.on('end',function (err,chunk) {
                    req.body = strPost;
                    G['_'+method][pathname](req,res);
                })
            }else{
                G['_' + method][pathname](req,res);
            }
        }else{
            res.end('no router');
        }
    };

    app.get = function (string, callback) {
        if(!string.endsWidth('/')){
            string = string + '/';
        }
        if(!string.startsWith('/')){
            string = '/' + string;
        }
        G._get[string] = callback;
    };
    app.post = function (string,callback) {
        if(!string.endsWidth('/')){
            string = string + '/';
        }
        if(!string.startsWith('/')){
            string = '/' + string;
        }
        G._post[string] = callback;
    };

    return app;
};

module.exports = Serve();

MongoDB 數(shù)據(jù)庫(kù)介紹、安裝、使用

NoSql介紹

由于互聯(lián)網(wǎng)的迅速發(fā),云計(jì)算與 Web2.0。這樣大量的交互數(shù)據(jù)給數(shù)據(jù)庫(kù)提出了更高的性能要求,傳統(tǒng)數(shù)據(jù)庫(kù),即關(guān)系型數(shù)據(jù)庫(kù)雖然具備良好的事物管理,但在處理大量數(shù)據(jù)的應(yīng)用時(shí)很難在性能上滿足設(shè)計(jì)要求。NoSQL 就是主要為了解決當(dāng)下大量高并發(fā)要求的數(shù)據(jù)應(yīng)用需求,關(guān)系數(shù)據(jù)庫(kù)具有嚴(yán)格的參照性,一致性,可用性,原子性,隔離性等特點(diǎn),因此會(huì)產(chǎn)生一些例如表鏈接等操作,這樣會(huì)大大降低系統(tǒng)性能。而在當(dāng)前很多應(yīng)用場(chǎng)景下對(duì)性能的要求遠(yuǎn)遠(yuǎn)強(qiáng)于傳統(tǒng)數(shù)據(jù)庫(kù)關(guān)注的點(diǎn)。 NoSQL 就是為了解決大規(guī)模數(shù)據(jù)與多樣數(shù)據(jù)種類等問(wèn)題,尤其是其中大數(shù)據(jù)的相關(guān)問(wèn)題。

NoSQL(not only sql) 它指的是非關(guān)系型數(shù)據(jù)庫(kù),是以 key-value 形式存儲(chǔ) 和傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)不一樣,不一定遵循傳統(tǒng)數(shù)據(jù)庫(kù)的一些基本要求,比如說(shuō)遵循 SQL標(biāo)準(zhǔn)、ACID屬性、表結(jié)構(gòu) 等等。NoSQL 最早提出是在20世紀(jì)80年代,在當(dāng)時(shí)更多是強(qiáng)調(diào)的是與關(guān)系型數(shù)據(jù)庫(kù)區(qū)別對(duì)待,最近這些年被提及的更多的是強(qiáng)調(diào)協(xié)助解決大數(shù)據(jù)等相關(guān)問(wèn)題。NoSQL 在大數(shù)據(jù)時(shí)代有自己的意義。

NoSQL 應(yīng)用情況介紹

國(guó)內(nèi)互聯(lián)網(wǎng)蓬勃發(fā)展,不僅涌現(xiàn)出 BAT 之類的巨頭,也帶動(dòng)了整個(gè)互聯(lián)網(wǎng)行業(yè)的發(fā)展,大量的創(chuàng)業(yè)共識(shí)如春筍般涌出。在國(guó)家層面也提出了 互聯(lián)網(wǎng)+萬(wàn)眾創(chuàng)業(yè) 的口號(hào)。更多傳統(tǒng)的行業(yè)也開(kāi)始擁抱互聯(lián)網(wǎng)。但是無(wú)論是所謂的生態(tài)平臺(tái)還是傳統(tǒng)業(yè)務(wù)的轉(zhuǎn)型,涉及到的業(yè)務(wù)是多種多樣的。這個(gè)時(shí)候企業(yè)架構(gòu)師對(duì)于應(yīng)用系統(tǒng)的核心——數(shù)據(jù)庫(kù)管理,不僅有傳統(tǒng)的 SQL 選項(xiàng)也有了 NoSQL 這種適合特定場(chǎng)景需求的選項(xiàng)。

NoSQL 數(shù)據(jù)庫(kù)在以下的幾種情況比較適用:

  • 數(shù)據(jù)模型比較簡(jiǎn)單
  • 需要靈活性更強(qiáng)的 IT 系統(tǒng)
  • 對(duì)數(shù)據(jù)庫(kù)性能要求較高
  • 不需要高度的數(shù)據(jù)一致性
  • 對(duì)于給定 key, 比較容易映射復(fù)雜值的環(huán)境

NoSQL 發(fā)展現(xiàn)狀

國(guó)外:Google 的 BigTable 和 Amazon 的 Dynamo 使用的就是 NoSQL 型數(shù)據(jù)庫(kù)。

國(guó)內(nèi):百度、阿里、騰訊、新浪微博、視覺(jué)中國(guó)、優(yōu)酷運(yùn)營(yíng)數(shù)據(jù)分析、豆瓣社區(qū)等..

什么時(shí)候建議使用 NoSQL

  • 對(duì)數(shù)據(jù)庫(kù)高并發(fā)讀寫(xiě)的需求
  • 對(duì)海量數(shù)據(jù)的高效存儲(chǔ)和訪問(wèn)的需求
  • 對(duì)數(shù)據(jù)庫(kù)的高可擴(kuò)展性和高可用性的需求

NoSQL和傳統(tǒng)數(shù)據(jù)庫(kù)簡(jiǎn)單對(duì)比

非結(jié)構(gòu)型數(shù)據(jù)庫(kù)。沒(méi)有行、列的概念。用 JSON 來(lái)存儲(chǔ)數(shù)據(jù)。

集合就相當(dāng)于“表”,文檔就相當(dāng)于“行”。

NoSQL 種類

MongoDB介紹

MongoDB 是一個(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ù)的。他支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類似 json 的 bson 格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類

型。Mongo 最大的特點(diǎn)是他支持的查詢語(yǔ)言非常強(qiáng)大,其語(yǔ)法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z(yǔ)言,幾乎可以

實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫(kù)單表查詢的絕大部分功能,而且還支持對(duì)數(shù)據(jù)建立索引。它的特點(diǎn)是高性能易部署、

易使用,存儲(chǔ)數(shù)據(jù)非常方便。

Mongodb安裝

Mongodb 基本操作

創(chuàng)建、使用數(shù)據(jù)庫(kù)

use sms

如果真想把這個(gè)數(shù)據(jù)庫(kù)創(chuàng)建成功,那么必須插入一個(gè)數(shù)據(jù)

數(shù)據(jù)庫(kù)中不能直接插入數(shù)據(jù),只能往集合(collection)中插入數(shù)據(jù)。不需要專門(mén)創(chuàng)建集合,只需要寫(xiě)點(diǎn)語(yǔ)法插入數(shù)據(jù)就會(huì)創(chuàng)建集合。

db.student.insert({name:'zhangsan'})

db.student系統(tǒng)發(fā)現(xiàn)student是一個(gè)陌生的集合名字,所以就會(huì)自動(dòng)創(chuàng)建了集合。

顯示當(dāng)前的數(shù)據(jù)集合:

show collections

刪除數(shù)據(jù)庫(kù),刪除當(dāng)前所在的數(shù)據(jù)庫(kù)

db.dropDatabase();

刪除集合,刪除指定的集合(刪除表)

db.student.drop();

插入(增加)數(shù)據(jù)

插入數(shù)據(jù),隨著數(shù)據(jù)的茶服,數(shù)據(jù)庫(kù)常見(jiàn)成功了,集合也創(chuàng)建成功了

db.表名.insert({name:'zhangsan'})

查找數(shù)據(jù)

1 查詢所有記錄

db.userInfo.find()  === select * from userInfo

2 查詢?nèi)ブ睾竽沉械臄?shù)據(jù)

db.userInfo.distinct('name') === select distict name from userInfo;

3 查詢 age = 18 的記錄

db.userInfo.find({age:22}) === select * from userInfo where age=18;

4 查詢 age > 18 的記錄

db.userInfo.find({age:{$gt:22}}) === select * from userInfo where age > 22;

5 查詢 age >= 18 的記錄

db.userInfo.find({age:{$gte:18}}) === select * from userInfo where age>=18;

6 查詢 age <= 18 的記錄

db.userInfo.find({age:{$lte:18}}) === select * from userInfo where age<=18;

7 查詢 age >=18 并且 age <= 20 的記錄

db.userInfo.find({age:{$gte:18,$lte:20}});

9 查詢 name 中包含 mongo 的數(shù)據(jù)

db.userInfo.find({name:/mongo/}) === select * from userInfo where name like '%mongo%';

10 查詢 name 中以 mongo 開(kāi)頭的

db.userInfo.find({name:/^mongo/}) === select * from userInfo where name like 'mongo%';

11 查詢指定列 name age 的數(shù)據(jù)

db.userInfo.find({},{name:1,age:1}) === select name,age from userInof;

當(dāng)然 name 也可以用 true 或 false, 當(dāng) true 的情況和 name:1 效果一樣, 如果用 false 就是排除 name,顯示 name 以外的列信息。

12 查詢指定列name、age 數(shù)據(jù),age > 25

db.userInfo.find({age:{$gt:25}},{name:1,age:1})

13 按照年齡排序 1 升序 -1 降序

db.userInfo.find().sort({age:1}) // 升序
db.userInfo.find().sort({age:-1}) //降序

14 查詢 name=zhangsan, age=22的數(shù)據(jù)

db.userInfo.find({name:'zhangsan',age:22}) === select * from userInfo where name='zhangsan' and age=22;

15 查詢前 5 條數(shù)據(jù)

db.userInfo.find().limit(5) === select top 5 * from userInfo;

16 查詢 10 條以后的數(shù)據(jù)

db.userInfo.find().skip(10) === select * from userInfo where id not in ( selct top 10 * from userInfo);

17 查詢?cè)?5-10 之間的數(shù)據(jù)

db.userInfo.find().limit(10).skip(5);

可用于分頁(yè),limit 是 pageSize,skip是第幾頁(yè) * pageSize

18 or 與 查詢

db.userInfo.find({$or:[{age:22},{age:25}]}) === select * from userInfo where age=22 or age=25;

19 findOne 查詢第一條數(shù)據(jù)

db.userInfo.findOne() === db.userInfo.find().limt(1)

20 查詢某個(gè)結(jié)果集的記錄條數(shù), 統(tǒng)計(jì)數(shù)量

db.userInfo.find({age:{$gte:25}}).count() === select count(*) from userInfo where age >= 20;

如果要返回限制之后的記錄數(shù)量,要使用 count(true) 或者 count(非0)

db.user.find().skip(10).limit(5).count(true);

修改數(shù)據(jù)

修改里面還有查詢條件。語(yǔ)法格式如下:

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í)別。

1 查找名字叫做小明,把年齡更改為16歲:

db.student.update({name:'小明'},{$set:{age:16}});

2 查詢數(shù)學(xué)成績(jī)是70,把年齡更改為33歲(只匹配修改一個(gè))

db.student.update({"score.shuxue":70},{$set:{age:18}});

3 更改所有匹配項(xiàng)目:

db.student.update({sex:'男'},{$set:{age:18,}},{multi:true});

4 完整替換,不出現(xiàn) $set 關(guān)鍵字: 注意

db.student.update({name:'小明'},{name:'大明',age:16});

db.users.update({name:'Lisi'},{$inc:{age:50}},false,true);
update users set age=age+50 where name = 'Lisi';

db.users.update({name:'Lisi'},{$inc:{age:50}, $set:{name:'hoho'}},false,true);
update users set age=age+50,name='hoho' where name='Liis';

刪除數(shù)據(jù)

db.collectionsNames.remove({'borough':'Manhattan'})

db.users.remove({age:12}) // 會(huì)刪除全部匹配項(xiàng)目
db.users.remove({age:12},{justOne:true}) // 刪除一個(gè)

MongoDB索引和explain的使用

索引基礎(chǔ)

索引是對(duì)數(shù)據(jù)庫(kù)表中一列或多列的值進(jìn)行排序的一種結(jié)構(gòu),可以讓我們查詢數(shù)據(jù)庫(kù)變得更快。MongoDB的索引幾乎與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)一樣,其中也包括一些基本的查詢優(yōu)化技巧

數(shù)據(jù)庫(kù)創(chuàng)建索引的缺點(diǎn),和什么時(shí)候不該創(chuàng)建索引

1 下面是創(chuàng)建索引的命令

db.user.ensureIndex({username:1});

2 獲取當(dāng)前集合的索引

db.user.getIndexes();

3 刪除索引的命令是

db.user.dropIndex({username:1});

4 在 Mongodb 中,我們同樣可以創(chuàng)建復(fù)合索引,如:

db.user.ensureIndex({username:1,age:-1})

數(shù)字1 表示 username 鍵的索引按升序排序存儲(chǔ),-1表示 age 鍵的索引按照降序方式存儲(chǔ)

該索引被創(chuàng)建后,基于username和age的查詢將會(huì)用到該索引,或者是基于username的查詢也會(huì)用到該索引,但是只是基于age的查詢將不會(huì)用到該復(fù)合索引。因此可以說(shuō),如果想用到復(fù)合索引,必須在查詢條件中包含復(fù)合索引中的前 N 個(gè)序列。然而如果查詢條件中的鍵值順序和復(fù)合索引中的創(chuàng)建順序不一致的話,MongoDB可以智能的幫助我們調(diào)節(jié)該順序,以便使復(fù)合索引可以為查詢所用。如:

db.user.find({age:30,username:'zhangsan'});

對(duì)于上面示例中的查詢條件。mongodb在檢索之前將會(huì)動(dòng)態(tài)的調(diào)整查詢文檔的順序,以使該查詢可以用到剛剛創(chuàng)建的復(fù)合索引。

對(duì)于上面的創(chuàng)建的索引,MongoDB都會(huì)根據(jù)索引的keyname和索引方向?yàn)樾聞?chuàng)建的索引自動(dòng)分配一個(gè)索引名,下面命令可以在創(chuàng)建索引時(shí)為其指定索引名,如:

db.user.ensureIndex({username:1},{name:'userIndex'});

隨著集合的增長(zhǎng),需要針對(duì)查詢中大量的排序做索引。如果沒(méi)有對(duì)索引的鍵調(diào)用sort,mongoDB需要將所有數(shù)據(jù)提取到內(nèi)存并排序。因此在做無(wú)索引排序時(shí),如果數(shù)據(jù)過(guò)大以至無(wú)法在內(nèi)存中進(jìn)行排序,此時(shí)mongoDB將會(huì)報(bào)錯(cuò)

mongodb中索引對(duì)range查詢和sort操作的影響

唯一索引

在缺省狀況下創(chuàng)建的索引均不是唯一索引。下面示例將創(chuàng)建唯一索引,如:

db.user.ensureIndex({userid:1},{unique:true});

如果再次插入 userid 重復(fù)的文檔時(shí),MongoDB將報(bào)錯(cuò),以提示插入重復(fù)鍵,如:

db.user.insert({userid:5})
db.user.insert({userid:5})
// E11000 duplicate key error index: user.user.$userid_1 dup key: { : 5.0  }

如果在創(chuàng)建唯一索引時(shí)存在了重復(fù)項(xiàng),我們可以通過(guò)以下的命令幫助我們?cè)趧?chuàng)建唯一索引時(shí)消除重復(fù)文檔,僅保留發(fā)現(xiàn)的第一個(gè)文檔,如:

先刪除剛創(chuàng)建的唯一索引

db.user.dropIndex({userid}:1)

插入測(cè)試數(shù)據(jù),以保證集合中有重復(fù)鍵存在

db.user.remove()
db.user.insert({userid:5})
db.user.insert({userid:6})

重新創(chuàng)建唯一索引

db.user.ensureIndex({userid:1},{dropDups:true})

我們同樣可以通過(guò)創(chuàng)建復(fù)合唯一索引,即保證復(fù)合鍵值唯一即可。如:

db.user.ensureIndex({userid:1,age:1},{unique:true})

索引的一些參數(shù)

使用explain

explain 是非常有用的工具,會(huì)幫助你獲得查詢方面諸多有用的信息。只要對(duì)游標(biāo)調(diào)用該方法,就可以查詢細(xì)節(jié)。explain會(huì)返回一個(gè)文檔,而不是游標(biāo)本身。如:

explain 會(huì)返回查詢使用的索引情況,耗時(shí)和掃描文檔數(shù)的統(tǒng)計(jì)信息。

explain executionStats 查詢具體的執(zhí)行時(shí)間

db.tablename.find().explain('executionStats')
關(guān)注輸出的如下數(shù)值:explain.executionStats.executionTimeMills

NodeJS 操作 MongoDB 數(shù)據(jù)庫(kù)

在 NodeJS 中使用MongoDB

npm install mongodb --save-dev

MongoDB 教程

MongDB 官方文檔

Koa 框架介紹

Node.js 是一個(gè)一步的世界,官方API支持的都是 callback 形式的異步編程,這會(huì)帶來(lái)很多問(wèn)題,例如:1 callback 嵌套問(wèn)題; 2、異步函數(shù)中可能存在同步調(diào)用callback返回來(lái)的數(shù)據(jù),帶來(lái)不一致。為了解決以上問(wèn)題 Koa 出現(xiàn)了。

Koa 基于Node.js平臺(tái)的下一代 Web 開(kāi)發(fā)框架

Koa 是有 Express 原班人馬打造,致力于成為一個(gè)更小,更富有表現(xiàn)力,更健壯的Web框架。使用Koa編寫(xiě)Web應(yīng)用,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套,并極大地提升錯(cuò)誤處理的效率。Koa 不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個(gè)輕量?jī)?yōu)雅的函數(shù)庫(kù),使得編寫(xiě)Web應(yīng)用變得得心應(yīng)手,開(kāi)發(fā)思路和express差不多,最大的特點(diǎn)就是可以避免異步嵌套。

>阿里是業(yè)界最早的一批使用 Node.js 來(lái)做線上大流量應(yīng)用的公司,早在 2011 年的就已經(jīng)開(kāi)始在生產(chǎn)環(huán)境中使用。 
>
>眾所周知,在阿里的技術(shù)棧中, Java 是最最核心的,那 Node.js 扮演怎么樣的一個(gè)角色呢? 
>
>1、基礎(chǔ)設(shè)施大部分采用 Java 實(shí)現(xiàn),變化較少,有事務(wù)要求的 Business Services 通常使用 
>
>Java。 
>
>2、而 Node.js 則替代過(guò)去 PHP/Java Web 的場(chǎng)景,用在需要快速迭代,需求變化非??斓?
>
>用戶側(cè)。
>
>3、很多內(nèi)部的工程化支撐系統(tǒng)也逐漸基于 Node.js 了。 
>
>據(jù)不完全統(tǒng)計(jì),目前阿里 Node.js 的開(kāi)發(fā)者幾百號(hào)人,線上的應(yīng)用也非常之多,僅次于 Java 應(yīng) 
>
>用,光對(duì)外服務(wù)的進(jìn)程數(shù)就超過(guò) 1w+。 
>
>阿里內(nèi)部就在使用 Koa 框架,并在 Koa 基礎(chǔ)上面做了一些擴(kuò)展和封裝。并且基于 koa 開(kāi)發(fā)了一個(gè) 
>
>開(kāi)源框架 egg。 

Koa 文檔

npm install koa --save-dev

Koa 路由

Koa路由與express中有所不同,在Express中直接引入Express說(shuō)就可以配置路由,但是在Koa中我們需要封裝對(duì)應(yīng)的 koa-router路由模塊來(lái)實(shí)現(xiàn)

npm install koa-router --save

一個(gè)簡(jiǎn)單使用的例子

/*
*  https://www.npmjs.com/package/koa-router
*  1 安裝模塊
*  2 看文檔使用
* */

/* 引入 Koa 模塊 */
const Koa = require('koa');
const router = require('koa-router')();

const app = new Koa();

router.get('/', async (ctx)=>{
    ctx.body = '這是首頁(yè)數(shù)據(jù)';
});

router.get('/news', async (ctx)=>{
    ctx.body = '這是新聞頁(yè)面數(shù)據(jù)';
});

router.get('/news_content', async (ctx)=>{
    /*
    * 在 Koa 中 GET 傳值通過(guò) request 接收,但是接收方法有兩種 query 和 querystring.
    * query: 返回格式化好的參數(shù)對(duì)象
    * querystring: 返回的是請(qǐng)求字符串
    *  */
    /* 從 ctx 里面 獲取 get 的傳值 */
    console.log(ctx.query);
    console.log(ctx.querystring);
    console.log(ctx.url);
    ctx.body = '12343354';
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000);

路由分層

對(duì)于一個(gè)完整的項(xiàng)目來(lái)說(shuō)如果所有的路由配置都寫(xiě)在一個(gè)文件中,這個(gè)文件無(wú)疑會(huì)變得很大,而且及其不容易維護(hù),所以我們需要對(duì)路由進(jìn)行模塊化的配置,這樣指責(zé)更加明確,維護(hù)也變得更加簡(jiǎn)單。

朋們?nèi)绻銈冇眠^(guò) react-router 或者 vue-router 那么 koa-router 對(duì)你們來(lái)說(shuō)就會(huì)非常簡(jiǎn)單,他們模塊化的思想是一樣的,前端的路由劃分模塊的形式是什么樣子的,koa-router 也一樣劃分就可以了,只是語(yǔ)法上有點(diǎn)不同而已。舉個(gè)例子:

一個(gè)項(xiàng)目中假如有 后臺(tái)管理模塊(admin) 前臺(tái)模塊(default) API模塊 (api)



后臺(tái)管理模塊又分為 user、focus、newscast 三個(gè)模塊,我們?cè)谶M(jìn)行路由劃分是可以按照如下目錄結(jié)構(gòu)



即當(dāng)我們?cè)O(shè)定視圖文件和我們的路由路徑是一樣的,這樣達(dá)成了一個(gè)統(tǒng)一,我們書(shū)寫(xiě)起來(lái)會(huì)很方便,查看該項(xiàng)目時(shí)也會(huì)很清晰。
/* app.js */

const path = require('path');
const Koa = require('koa');
const router = require('koa-router')();
const render = require('koa-art-template');

/* 路由模塊 start */
const index = require('./routes/index');
const api = require('./routes/api');
const admin = require('./routes/admin');
/* 路由模塊 end */

const app = new Koa();
render(app,{
    root: path.resolve(__dirname, 'views'),
    extname: '.html',
    debug: process.env.NODE_ENV !== 'production'
});


router.use('/', index); 
router.use('/api', api);
router.use('/admin', admin); // 在 /admin 根路由下使用 admin 路由

/* 最后處理無(wú)匹配頁(yè)面 */
router.get('*', async (ctx)=>{
    ctx.body = '<h2>404</h2>'
});

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);
/* admin.js */

const router = require('koa-router')();

const user = require('./admin/user');
const focus = require('./admin/focus');
const newscate = require('./admin/newscate');

router.use('/user', user);  // 在此路由下使用 user 的路由
router.use('/newscate', newscate);
router.use('/focus', focus);

module.exports = router.routes();

/* admin/user.js */
const router = require('koa-router')();

router.get('/', async (ctx)=>{
    await ctx.render('admin/user/index')
});

router.get('/add', async (ctx)=>{
    await ctx.render('admin/user/add')
});

router.get('/edit', async (ctx)=>{
    await ctx.render('admin/user/edit')
});

router.get('/delete', async (ctx)=>{
    ctx.body = '刪除這是刪除頁(yè)面'
});

module.exports = router.routes();

Koa中間件

1 什么是中間件

通俗的講:中間件就是在匹配路由之前或者匹配路由完成的一系列操作,我們就可以把它叫做中間件。

在 express 中間件是一個(gè)函數(shù),他可以訪問(wèn)請(qǐng)求對(duì)象 req 和 res,和 Web 應(yīng)用中處理請(qǐng)求-響應(yīng)循環(huán)流程的中間件,一般命名為 next 的變量。在 Koa 中中間件和 express 有點(diǎn)類似。

中間件的功能包括

 * 執(zhí)行任何代碼
 * 修改請(qǐng)求和響應(yīng)對(duì)象
 * 終結(jié)請(qǐng)求-響應(yīng)循環(huán)

如果我的 get、post回調(diào)函數(shù)中,沒(méi)有 next 參數(shù),那么就匹配上第一個(gè)路由,就不會(huì)往下匹配了。如果想往下匹配的話,那么就必須要寫(xiě) next();

2 Koa 應(yīng)用可以使用如下幾種中間件

 * 應(yīng)用級(jí)中間件

 * 路由級(jí)中間件

 * 錯(cuò)誤處理中間件

 * 第三方中間件

應(yīng)用級(jí)中間件


路由中間件

錯(cuò)誤處理中間件

第三方中間件

3 Koa中間件執(zhí)行順序

Koa 的中間件和 Express 不同,Koa 選擇了洋蔥圈模型。

中間件洋蔥圖:

Koa 靜態(tài)資源

通過(guò)使用 koa-staitc 靜態(tài)資源中間件可以統(tǒng)一管理靜態(tài)資源,無(wú)須自己配置靜態(tài)文件的讀寫(xiě)

1 安裝 koa-static

npm install koa-static --save

2 引入 koa-static 配置中間件

const static = require('koa-static');

3 配置中間件

const path = require('path');
const Koa = require('koa');
const statics = require('koa-static');
app.use(statics(path.resolve(__dirname, 'static'))) // 參數(shù)是文件路徑

Koa 中使用 ejs模板

1 安裝 koa-views 和 ejs

npm install --save koa-views
npm install ejs --save

2 引入 koa-views 配置中間件

const views = require('koa-views');
app.use(views,{map:{html:'ejs'}});

3 koa中使用 ejs:

router.get('/add',async (ctx)=>{
    let title = 'hello world';
    await ctx.render('index',{title})
})

Ejs 文檔
koa-views 文檔

Koa post 提交數(shù)據(jù) body-parser 中間件使用

koa-bodypase 文檔

安裝 koa-bodyparser

npm install koa-bodypaeser --save

安裝 引入配置中間件

var Koa = require('koa'); 
var bodyParser = require('koa-bodyparser'); 
var app = new Koa(); 
app.use(bodyParser()); 

使用

ctx.request.body 獲取 post 提交的數(shù)據(jù)

koa art-template 模板引擎

常見(jiàn)模版引擎的性能對(duì)比

適用于 koa 的模板引擎的選擇非常多,比如 jade、ejs、nunchucks、art-template 等。

Art-template 是一個(gè)簡(jiǎn)約、超快的模板引擎。

它采用作用域生命的技術(shù)來(lái)優(yōu)化模板渲染速度,從而獲得僅僅javascript極限的運(yùn)行性能,并且同時(shí)支持NodeJS和瀏覽器。

Art-template 支持ejs的語(yǔ)法,可以用自己類似 angular 數(shù)據(jù)綁定的語(yǔ)法。

官網(wǎng):http://aui.github.io/art-template/

中文文檔: http://aui.github.io/art-template/zh-cn/docs/



在 Koa 中使用 art-template 模板引擎

npm install art-template --save
npm install koa-art-template --save

const Koa = require('koa');
const render = require('koa-art-template');

const app = new Koa();
render({
    root: path.join(__dirname, 'view'),
    extname:'.art', //后綴名
    debugger:process.env.NODE_ENV != 'production'
});

app.use(async function(ctx){
    await ctx.render('user');
});

app.listen(3000);

art-template m模板引擎語(yǔ)法
參考:http://aui.github.io/art-template/zh-cn/docs/syntax.html

Koa 中 Cookie 的使用

Cookie 簡(jiǎn)介

cookie 是存儲(chǔ)于訪問(wèn)者計(jì)算機(jī)中的變量??梢宰屛覀冇猛粋€(gè)瀏覽器訪問(wèn)同一個(gè)域名的時(shí)候共享數(shù)據(jù)。

http是無(wú)狀態(tài)協(xié)議。簡(jiǎn)單的說(shuō),當(dāng)你瀏覽了一個(gè)頁(yè)面,然后轉(zhuǎn)到同一個(gè)網(wǎng)站的另一個(gè)頁(yè)面,服務(wù)器無(wú)法認(rèn)識(shí)到這是同一個(gè)瀏覽器在訪問(wèn)同一個(gè)網(wǎng)站,每一次的訪問(wèn),都是沒(méi)有任何關(guān)系的。

Koa Cookie 的使用

1 Koa中設(shè)置 Cookie 的值

ctx.cookies.set(name, value, [options])

通過(guò) options 設(shè)置,cookie name 的 value


2 Koa 中獲取 Cookie 的值

ctx.cookies.get('name');

3 Koa 中設(shè)置中文 Cookie

console.log(new Buffer('hello, world!').toString('base64'));// 轉(zhuǎn)換成 base64 字符 串:aGVsbG8sIHdvcmxkIQ== 

console.log(new Buffer('aGVsbG8sIHdvcmxkIQ==', 'base64').toString());// 還原 base 64 字符串:hello, world!

Koa session 的使用

session 簡(jiǎn)單介紹
session 是另一種記錄客戶狀的機(jī)制,不同的是cookie保存在客戶端瀏覽器中,而session保存在服務(wù)器上。

session的工作流程
當(dāng)瀏覽器訪問(wèn)服務(wù)器并發(fā)送一次請(qǐng)求是,服務(wù)器端會(huì)創(chuàng)建一個(gè)session對(duì)象,生成類似一個(gè)key value的鍵值對(duì),然后將key(cookie)返回到瀏覽器端,瀏覽器下次再訪問(wèn)是,攜帶key,找到對(duì)應(yīng)的session??蛻舻男畔⒍急4嬖趕ession中。

Koa-session 的使用 文檔
1 安裝 express-session

npm install koa-session --save

2 引入 express-session

const session = require('koa-session')

3 設(shè)置官方文檔提供的中間件

app.keys = ['somej secret hurr'];
const config = {
  key:'koa:sess', // cookie key (default is koa:sess)
  maxAge:8640000, // cookie 的過(guò)期時(shí)間 maxAge in ms (default is 1 days)
  overwrite: true, //是否可以 overwrite (默認(rèn) default true)
  httpOnly:true, //cookie 是否只有服務(wù)器端可以訪問(wèn) httpOnly or not (default true)
  signed: true, //簽名默認(rèn) true
  rolling: false, //在每次請(qǐng)求時(shí)強(qiáng)行設(shè)置 cookie,這將重置 cookie 過(guò)期時(shí)間(默認(rèn):false) 
  renew: false, //(boolean) renew session when session is nearly expired,
}

app.use(session(config,app));

4 使用

ctx.session.username = '張三';//設(shè)置
ctx.session.username //獲取

文章源碼地址:https://gitee.com/hanway/NodeJS

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容