nodejs、數據庫(基本指令)基礎要點總結

 
這是一個md文件 你們以爲須要能夠直接複製粘貼到md文件下用html打開看,這樣效果會好點
 
 

 

 
### 客戶端的JavaScript是怎樣的

- 什麼是 JavaScript?
+是一個腳本語言
+運行在瀏覽器(瀏覽器的js解析內核 v8)
+實現用戶的交互 (interactive)
+ 變量 賦值 循環 邏輯 判斷 分支 對象 函數。。。。
+ dom 操做
+ bom 操做
+ ajax
- JavaScript 的運行環境?
+瀏覽器內核解析內核 es6

- 瀏覽器中的 JavaScript 能夠作什麼?


- 瀏覽器中的 JavaScript 不能夠作什麼?(不安全)
+訪問數據庫
+不能對文件進行操做
+對os 進行操做
+緣由 是不安全 和瀏覽器運行機制有關
- 在開發人員能力相同的狀況下編程語言的能力取決於什麼?

+cordova hbuilder 平臺 platform
+java java虛擬機 (運行平臺)
+php php虛擬機
+c# .net framework mono
+js 解析內核 chrome v8
- JavaScript 只能夠運行在瀏覽器中嗎?
+不是

### 爲何是JavaScript
+ node js 不是由於js 產生的
+ node 選擇了js
+ Ryan dahl
+ 2009 2 月份 node有想法
+ 2009 5 月份 githup 開源
+ 2009 11月份 jsconf 講解推廣node
+ 2010年末 被xxx公司收購
+ 2018 發佈有重大bug
+ npm
+ githup 世界上最大的同性交友網站 碼雲

### what is node ?

- Node.js 是一個基於Chrome V8 引擎的JavaScript運行環境
- Node.js使用了一個事件驅動、非阻塞式I/O的模型,使其輕量又高效
- Node.js的包管理工具npm,是全球最大的開源庫生態系統
- 官網 http://nodejs.cn/
- npm 插件官網:https://www.npmjs.com/

## 環境配置

### Node的安裝

- 安裝包安裝
+ 官網下載對應的安裝包
+ 一路next
- nvm安裝(有一個相似的工具:n)
+ Node Version Manager(Node版本管理工具)
+ 因爲之後的開發工做可能會在多個Node版本中測試,並且Node的版本也比較多,因此須要這麼款工具來管理
+
### 相關版本

- node版本常識
+ 偶數版本爲穩定版 (0.6.x ,0.8.x ,0.10.x)
+ 奇數版本爲非穩定版(0.7.x ,0.9.x ,0.11.x)
+ LTS(Long Term Support)
+ [LTS和Current區別](https://blog.csdn.net/u012532033/article/details/73332099)
- 操做方式:
+ 從新下載最新的安裝包;
+ 覆蓋安裝便可;
- 問題:
+ 之前版本安裝的不少全局的工具包須要從新安裝
+ 沒法回滾到以前的版本
+ 沒法在多個版本之間切換(不少時候咱們要使用特定版本)

### Windows下經常使用的命令行操做

- 切換當前目錄(change directory):cd
- 建立目錄(make directory):mkdir
- 查看當前目錄列表(directory):dir
+ 別名:ls(list)
- 清空當前控制檯:cls
+ 別名:clear
- 刪除文件:del
+ 別名:rm

> 注意:全部別名必須在新版本的 PowerShell (linux系統)中使用

### 常見問題
- Python環境丟失
+ Node中有些第三方的包是以C/C++源碼的方式發佈的,須要安裝後編譯,確保全局環境中可使用python命令,python 版本推薦2.7.0
- 環境變量丟失
+ 部分電腦安裝完畢以後沒有環境變量須要手動配置
+ Windows中環境變量分爲系統變量和用戶變量
+ 環境變量的變量名是不區分大小寫的
+ PATH 變量:只要添加到 PATH 變量中的路徑,均可以在任何目錄下
+ 目的能夠在任何地方調起node命令

>
##模塊,包 commonjs

### commonjs規範

前端模塊化:AMD,CMD,Commonjs

Node 應用由模塊組成,採用 CommonJS 模塊規範。

##### 定義module

每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。

##### 暴露接口

CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports屬性。

```javascript
 var x = 5;
  var addX = function (value) {
   return value + x;
  };
  module.exports.x = x;
  module.exports.addX = addX;
```
##### 引用

require方法用於加載模塊。

```
 var example = require('./example.js');
  console.log(example.x); // 5
  console.log(example.addX(1)); // 6
```
### 模塊的分類

* 內置模塊
```
  const process = require('process')
  const path = require('path')
  console.log(process.version)
  console.log(path.resolve('../'))
```
* 第三方模塊
```
const request=require("request");
  console.log(request)
  request.get('http://api.douban.com/v2/movie/in_theaters', (err, response, body) => {
   if (!err) {
   // console.log(body);
   console.log(JSON.parse(body))
   } else {
   console.log(err);
   }
  })
```
* 自定義模塊

###npm 使用入門

官網:[https://www.npmjs.com/](https://www.npmjs.com/)

安裝:無需安裝

查看當前版本:

```
$ npm -v
```

更新:

```
$ npm install npm@latest -g

```
初始化工程

```
$ npm init

$ npm init --yes 默認配置
```

安裝包

使用npm install會讀取package.json文件來安裝模塊。安裝的模塊分爲兩類
dependencies和devDependencies,分別對應生產環境須要的安裝包和開發環境須要的安裝包。

```
$ npm install

$ npm install <package_name>

$ npm install <package_name> --save

$ npm install <package_name> --save-dev
```
更新模塊

```
$ npm update
```
卸載模塊

```
$ npm uninstall <package_name>

$ npm uninstall --save lodash
```

配置npm源

* 臨時使用, 安裝包的時候經過--registry參數便可

  $ npm install express --registry https://registry.npm.taobao.org

* 全局使用
  ```
   $ npm config set registry https://registry.npm.taobao.org
   // 配置後可經過下面方式來驗證是否成功
   npm config get registry
   // 或
   npm info express
  ```

* cnpm 使用
```
   // 安裝cnpm
     npm install -g cnpm --registry=https://registry.npm.taobao.org

     // 使用cnpm安裝包
     cnpm install express
```

>

### 經常使用的內置模塊

node 經常使用內置api

(1) URL 網址解析
解析URL相關網址信息
url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
url.format(urlObject)
url.resolve(from, to)
(2) QueryString 參數處理
querystring.escape(str) //編碼解碼
querystring.unescape(str)
querystring.parse(str[, sep[, eq[, options]]])
querystring.stringify(obj[, sep[, eq[, options]]])
(3) HTTP 模塊概要
  http.createServer([options][, requestListener])
  http.get(options[, callback])
  簡易的爬蟲
代理跨域處理
(4) 事件 events 模塊
(5) 文件fs模塊
打印目錄樹
(6) Stream 流模塊
歌詞播放
音樂下載
(8) request 方法


二、Node.js 基礎應用
一、應用 HTTP 模塊編寫一個小爬蟲工具
(1) 利用爬蟲獲取「拉勾網」首頁列表數據
(2) 經過 npm 安裝 cheerio 模塊得到數據
二、後端表單的提交
要求:
(1) 應用 request post 模擬提交表單

### 文件讀取

Node中文件讀取的方式主要有:

> fs.readFile(file[, options], callback(error, data))

```javascript
fs.readFile('c:\\demo\1.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);//獲得二進制buffer
});
```

> fs.readFileSync(file[, options])

```javascript
try {
const data = fs.readFileSync('c:\\demo\1.txt', 'utf8');
console.log(data);
} catch(e) {
// 文件不存在,或者權限錯誤
throw e;
}
```

> fs.createReadStream(path[, options])

```javascript
const stream = fs.createReadStream('c:\\demo\1.txt');
let data = ''
stream.on('data', (trunk) => {
data += trunk;
});
stream.on('end', () => {
console.log(data);
});
```

> *因爲Windows平臺下默認文件編碼是GBK,在Node中不支持,能夠經過[iconv-lite](https://github.com/ashtuchkin/iconv-lite)解決*


### Readline模塊逐行讀取文本內容

```javascript
const readline = require('readline');
const fs = require('fs');

const rl = readline.createInterface({
input: fs.createReadStream('sample.txt')
});

rl.on('line', (line) => {
console.log('Line from file:', line);
});
```


### 文件寫入

Node中文件寫入的方式主要有:

> fs.writeFile(file, data[, options], callback(error))

```javascript
fs.writeFile('c:\\demo\a.txt', new Date(), (error) => {
console.log(error);
});
```

> fs.writeFileSync(file, data[, options])

```javascript
try {
fs.writeFileSync('c:\\demo\a.txt', new Date());
} catch (error) {
// 文件夾不存在,或者權限錯誤
console.log(error);
}
```

> fs.createWriteStream(path[,option])

```javascript
var streamWriter = fs.createWriteStream('c:\\demo\a.txt');
setInterval(() => {
streamWriter.write(`${new Date}\n`, (error) => {
console.log(error);
});
}, 1000);
```
###node中的異步操做


- fs模塊對文件的幾乎全部操做都有同步和異步兩種形式
- 例如:readFile() 和 readFileSync()
- 區別:
+ 同步調用會阻塞代碼的執行,異步則不會
+ 異步調用會將讀取任務下達到任務隊列,直到任務執行完成纔會回調
+ 異常處理方面,同步必須使用 try catch 方式,異步能夠經過回調函數的第一個參數

```javascript
console.time('sync');
try {
var data = fs.readFileSync(path.join('C:\\Users\\iceStone\\Downloads', 'H.mp4'));
// console.log(data);
} catch (error) {
throw error;
}
console.timeEnd('sync');

console.time('async');
fs.readFile(path.join('C:\\Users\\iceStone\\Downloads', 'H.mp4'), (error, data) => {
if (error) throw error;
// console.log(data);
});
console.timeEnd('async');
```
##### promise 對象的使用

參考資料:[JavaScript Promise迷你書](http://liubin.org/promises-book/#what-is-promise)

* what is Promise *
Promise是抽象異步處理對象以及對其進行各類操做的組件。Promise並非從JavaScript中發祥的概念。
Promise最初被提出是在 E語言中, 它是基於並列/並行處理設計的一種編程語言。
如今JavaScript也擁有了這種特性,這就是JavaScript Promise

使用了回調函數的異步處理

```javascript

----
getAsync("fileA.txt", function(error, result){
if(error){// 取得失敗時的處理
throw error;
}
// 取得成功時的處理
});
----
<1> 傳給回調函數的參數爲(error對象, 執行結果)錯誤優先處理
```

使用了回調函數的異步處理

```javascript
----
var promise = getAsyncPromise("fileA.txt");
promise.then(function(result){
// 獲取文件內容成功時的處理
}).catch(function(error){
// 獲取文件內容失敗時的處理
});
----
<1> 返回promise對象
```

* 建立Promise對象 *

```
var promise = new Promise(function(resolve, reject) {
// 異步處理
// 處理結束後、調用resolve 或 reject
resolve('成功處理')
reject('錯誤處理')
});
```
* 使用實例 *

1. 建立一個priomise 對象並返回`new Promise(fn)`
2. 在fn 中指定異步等處理
  * 處理結果正常的話,調用`resolve(處理結果值)`
  * 處理結果錯誤的話,調用 `reject(Error對象)`

```javascript
function asyncFunction() {
 
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Async Hello world');
}, 16);
});
}

asyncFunction().then(function (value) {
console.log(value); // => 'Async Hello world'
}).catch(function (error) {
console.log(error);
});
```

* Promise的狀態

用new Promise 實例化的promise對象有如下三個狀態。

* **"has-resolution" - Fulfilled** resolve(成功)時。

* **"has-rejection" - Rejected** reject(失敗)時

* **"unresolved" - Pending** 既不是resolve也不是reject的狀態。也就是promise對象剛被建立後的初始化狀態等

promise對象的狀態,從Pending轉換爲Fulfilled或Rejected以後, 這個promise對象的狀態就不會再發生任何變化。

也就是說,Promise與Event等不一樣,在.then 後執行的函數能夠確定地說只會被調用一次。

另外,Fulfilled和Rejected這兩個中的任一狀態均可以表示爲Settled(不變的)。

Settled
resolve(成功) 或 reject(失敗)。

從Pending和Settled的對稱關係來看,Promise狀態的種類/遷移是很是簡單易懂的。

當promise的對象狀態發生變化時,用.then 來定義只會被調用一次的函數。

### 路徑模塊

在文件操做的過程當中,都必須使用物理路徑(絕對路徑),path模塊提供了一系列與路徑相關的 API

```javascript
console.log('join用於拼接多個路徑部分,並轉化爲正常格式');
const temp = path.join(__dirname, '..', 'lyrics', './友誼之光.lrc');
console.log(temp);

console.log('獲取路徑中的文件名');
console.log(path.basename(temp));

console.log('獲取路徑中的文件名並排除擴展名');
console.log(path.basename(temp, '.lrc'));

console.log('====================================');

console.log('獲取不一樣操做系統的路徑分隔符');
console.log(process.platform + '的分隔符爲 ' + path.delimiter);

console.log('通常用於分割環境變量');
console.log(process.env.PATH.split(path.delimiter));

console.log('====================================');

console.log('獲取一個路徑中的目錄部分');
console.log(path.dirname(temp));

console.log('====================================');

console.log('獲取一個路徑中最後的擴展名');
console.log(path.extname(temp));

console.log('====================================');

console.log('將一個路徑解析成一個對象的形式');
const pathObject = path.parse(temp);
console.log(pathObject);

console.log('====================================');

console.log('將一個路徑對象再轉換爲一個字符串的形式');
// pathObject.name = '我終於失去了你';
pathObject.base = '我終於失去了你.lrc';
console.log(pathObject);

console.log(path.format(pathObject));

console.log('====================================');

console.log('獲取一個路徑是否是絕對路徑');
console.log(path.isAbsolute(temp));
console.log(path.isAbsolute('../lyrics/愛的代價.lrc'));

console.log('====================================');

console.log('將一個路徑轉換爲當前系統默認的標準格式,並解析其中的./和../');
console.log(path.normalize('c:/develop/demo\\hello/../world/./a.txt'));

console.log('====================================');

console.log('獲取第二個路徑相對第一個路徑的相對路徑');
console.log(path.relative(__dirname, temp));

console.log('====================================');

console.log('以相似命令行cd命令的方式拼接路徑');
console.log(path.resolve(temp, 'c:/', './develop', '../application'));

console.log('====================================');

console.log('獲取不一樣平臺中路徑的分隔符(默認)');
console.log(path.sep);

console.log('====================================');

console.log('容許在任意平臺下以WIN32的方法調用PATH對象');
// console.log(path.win32);
console.log(path === path.win32);

console.log('====================================');

console.log('容許在任意平臺下以POSIX的方法調用PATH對象');
console.log(path === path.posix);
```

### express

---

官網:[http://www.expressjs.com.cn/](http://www.expressjs.com.cn/)


#### express 環境搭建

安裝

```bash
  $ npm install express --save
```

快速開始

```javascript
  const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
```

#### express 路由配置


```javascript
let express=require('express')
let router=express.Router()
// 該路由使用的中間件
router.use((req,res,next)=>{
   next()
});
// 定義網站主頁的路由
router.post('/addFood', function(req, res) {
  console.log('hahaha')
// res.send('這裏是admin的登陸');
});
// 定義 about 頁面的路由
router.post('/regist', function(req, res) {
res.send('這裏是admin的註冊側');
});

module.exports = router;

app.use('/admin',admin)
```

#### 傳遞數據的獲取

  get
  req.query
  post
  req.body
  body-parser
  
  設置中文格式
  res.set('Content-Type','text/plain,charset=utf8')

#### 請求模擬工具 postman

#### 靜態資源配置

```javascript

app.use(express.static('public'))

app.use('/static', express.static('public'))

app.use('/static', express.static(path.join(__dirname, 'public')))

```

## mongod

### 安裝配置
> 在`Mongodb`官網下載最新版本的[Mongodb下載地址](https://cloud.mongodb.com/)
>
> 下載`msi`的`window`安裝包,能夠裝到C盤或者D盤目錄下
>
> # 配置
> 因爲我是安裝在D盤的環境下
>
> ```shell
> D:\Program Files (x86)\MongoDB\Server\3.2\bin
> ```
>
> 因此在bin文件夾下找到mongod.exe命令,而後經過管理員執行`mongod --dbpath x路徑x`,路徑能夠是任何地方,我這裏選擇在D盤的MongoDB目錄下,固然路徑不要包含特殊的字符串,好比`Program Files (x86)`也不行
>
> ```shell
> mongod --dbpath D:\mongodb\data\db
> ```
>
> ![image](https://user-images.githubusercontent.com/17243165/31977540-fc0a5a6e-b96f-11e7-9a2b-34d66d7241c4.png)
>
> # 命令行
> 通過上面的配置以後,就能夠返回bin目錄下找到`mongo.exe`命令,並管理員下執行,就能夠出現mongodb的命令行模式
>
> ```shell
> D:\Program Files (x86)\MongoDB\Server\3.2\bin
> ```
>
> ![image](https://user-images.githubusercontent.com/17243165/31978099-57bce3ca-b972-11e7-88bd-30f5d68036ed.png)
>
> 而後就可使用下面的命令來測試了
>
### mongod
> ```js
> db.help()//幫助
> db.stats()//統計
> ```
>
> # 顯示數據庫
> ```js
> show dbs
> ```
>
> 檢查當前選擇的數據庫
>
> ```js
> db
> ```
>
> # 添加數據庫
> **數據庫名**爲數據庫建立的名字,使用該命令後會默認切換到對應的數據庫,而且在數據庫中添加選項,數據庫信息才顯示,若是默認就有該數據庫,那就是切換到對應的數據庫裏面
>
> ```js
> use 數據庫名
> ```
>
> # 刪除數據庫
> 先切換到對應的數據庫,而後再執行`db.dropDatabase()`刪除該數據庫
>
> ```js
> use 數據庫名
> //switched to db 數據庫名
> db.dropDatabase()
> ```
>
> # 顯示集合
> 用一下命令能夠檢查建立的集合
>
> ```js
> show collections
> ```
>
> # 添加集合
> 在建立完數據庫以後,咱們就能夠建立集合
>
> ```js
> db.createCollection(集合名字name,設置參數options[對象類型])
> ```
>
> **name**是要建立的集合的名稱。 **options**是一個文檔,用於指定集合的配置
>
> 參數  類型  描述
> name  String  要建立的集合的名稱
> options Document  (可選)指定有關內存大小和索引的選項
> **options**參數是可選的,所以只須要指定集合的名稱。 如下是可使用的選項列表:
>
> 字段  類型  描述
> capped  Boolean (可選)若是爲true,則啓用封閉的集合。上限集合是固定大小的集合,它在達到其最大大小時自動覆蓋其最舊的條目。 若是指定true,則還須要指定size參數。
> autoIndexId Boolean (可選)若是爲true,則在_id字段上自動建立索引。默認值爲false。
> size  數字  (可選)指定上限集合的最大大小(以字節爲單位)。 若是capped爲true,那麼還須要指定此字段的值。
> max 數字  (可選)指定上限集合中容許的最大文檔數。
> 因爲**option**是可選,咱們也能夠不帶配置項建立集合
>
> ```js
> db.createCollection("mycollection")
> ```
>
> # 刪除集合
> `db.collection.drop()`用於從數據庫中刪除集合
>
> ```js
> db.集合名.drop()
> ```
>
> 好比咱們能夠測試如下操做
>
> ```js
> db.createCollection("wscats")//建立名爲wscats的集合
> show collections//顯示該數據庫全部集合 wscats
> db.wscats.drop()//刪除名爲wscats的集合
> ```
>
> # 查看文檔
> 最簡單查看文檔的方法就是`find()`,會檢索集合中全部的文檔結果
>
> ```js
> db.集合名.find()
> ```
>
> 要以格式化的方式顯示結果,可使用`pretty()`方法。
>
> ```js
> db.集合名.find().pretty()
> ```
>
> ## 1.固值尋找
> 尋找age集合裏面全部含有屬性值爲wscats的文檔結果,至關於`where name = 'wscats'`
>
> ```js
> db.age.find({name:"wscats"})
> ```
>
> ## 2.範值尋找
> 操做  語法  示例  等效語句
> 相等  {:} `db.age.find({"name":"wscats"}).pretty()` where name = 'wscats'
> 小於  {:{$lt:}} `db.age.find({"likes":{$lt:50}}).pretty()`  where likes < 50
> 小於等於  {:{$lte:}}  `db.age.find({"likes":{$lte:50}}).pretty()` where likes <= 50
> 大於  {:{$gt:}} `db.age.find({"likes":{$gt:50}}).pretty()`  where likes > 50
> 大於等於  {:{$gte:}}  `db.age.find({"likes":{$gte:50}}).pretty()` where likes >= 50
> 不等於 {:{$ne:}} `db.age.find({"likes":{$ne:50}}).pretty()`  where likes != 50
> ## 3.AND和OR尋找
> ### AND
> 在find()方法中,若是經過使用`,`將它們分開傳遞多個鍵,則mongodb將其視爲**AND**條件。 如下是AND的基本語法
>
> 尋找`_id`爲1而且`name`爲wscats的全部結果集
>
> ```js
> db.age.find(
> {
> $and: [
> {"_id": 1}, {"name": "wscats"}
> ]
> }
> )
> ```
>
> ### OR
> 在要根據OR條件查詢文檔,須要使用`$or`關鍵字。如下是OR條件的基本語法
>
> 尋找`name`爲corrine或者`name`爲wscats的全部結果集
>
> ```js
> db.age.find(
> {
> $or: [
> {"name": "corrine"}, {「name「: "wscats"}
> ]
> }
> )
> ```
>
> ### AND和OR等結合
> 至關於語句`where title = "wscats" OR ( title = "corrine" AND _id < 5)`
>
> ```js
> db.age.find({
> $or: [{
> "title": "wscats"
> }, {
> $and: [{
> "title": "corrine"
> }, {
> "_id": {
> $lte: 5
> }
> }]
> }]
> })
> ```
>
> # 插入文檔
> 文檔的數據結構和JSON基本同樣。
> 全部存儲在集合中的數據都是BSON格式。
> BSON是一種類json的一種二進制形式的存儲格式,簡稱**Binary JSON**。
>
> 要將數據插入到mongodb集合中,須要使用mongodb的`insert()`或`save()`方法。
>
> ```js
> db.集合名.insert(document)
> ```
>
> 好比咱們能夠插入如下數據
>
> ```js
> db.wscats.insert({
> _id: 100,
> title: 'MongoDB Tutorials',
> description: 'node_tutorials',
> by: 'Oaoafly',
> url: 'https://github.com/Wscats/node-tutorial',
> tags: ['wscat','MongoDB', 'database', 'NoSQL','node'],
> num: 100,
> })
> ```
>
> 也能夠支持插入多個,注意傳入的是數組形式
>
> ```js
> db.wscats.insert([{
> _id: 100,
> title: ‘Hello’
> },{
> _id: 101,
> title: ‘World’
> }])
> ```
>
> 在插入的文檔中,若是不指定_id參數,那麼mongodb會爲此文檔分配一個惟一的ObjectId
> 要插入文檔,也可使用`db.post.save(document)`。若是不在文檔中指定_id,那麼`save()`方法將與`insert()`方法同樣自動分配ID的值。若是指定_id,則將以save()方法的形式替換包含**_id**的文檔的所有數據。
>
> ```js
> db.wscats.save({
> _id: 111,
> title: 'Oaoafly Wscats',
> })
> ```
>
> # 更新文檔
> ## 1.update()方法
> 尋找第一條title爲wscats的值,而且更新值title爲corrine和age爲12
>
> ```js
> db.age.update({
> 'title': 'wscats'
> }, {
> $set: {
> 'title': 'corrine',
> 'age': 12
> }
> })
> ```
>
> 默認狀況下,mongodb只會更新一個文檔。要更新多個文檔,須要將參數`multi`設置爲true,還能夠配合find方法裏面的各類複雜條件判斷來篩選結果,而後更新多個文檔
>
> 尋找全部title爲wscats的值,而且更新值title爲corrine和age爲12
>
> ```js
> db.age.update({
> 'title': 'wscats'
> }, {
> $set: {
> 'title': 'corrine',
> 'age': 12
> }
> }, {
> multi: true
> })
> ```
>
> ## 2.save()方法
> 將`_id`主鍵爲3的文檔,覆蓋新的值,注意`_id`爲必傳
>
> ```
> db.age.save({
> '_id':3,
> 'title': 'wscats'
> })
> ```
> # 刪除文檔
> 刪除主鍵`_id`爲3的文檔,默認是刪除多條
>
> ```js
> db.age.remove({
> '_id':3
> })
> ```
>
> 建議在執行`remove()`函數前先執行`find()`命令來判斷執行的條件是否正確
>
> 若是你只想刪除第一條找到的記錄能夠設置**justOne**爲1,以下所示
>
> ```js
> db.age.remove({...},1)
> ```
>
> 所有刪除
>
> ```js
> db.age.remove({})
> ```
>
> # Limit與Skip方法
> ## Limit
> 若是你須要在mongodb中讀取指定數量的數據記錄,可使用mongodb的Limit方法,`limit()`方法接受一個數字參數,該參數指定從mongodb中讀取的記錄條數。
>
> ```js
> db.age.find().limit(數量)
> ```
>
> ## Skip
> 咱們除了可使用`limit()`方法來讀取指定數量的數據外,還可使用`skip()`方法來跳過指定數量的數據,skip方法一樣接受一個數字參數做爲跳過的記錄條數。
>
> ```js
> db.age.find().limit(數量).skip(數量)
> //skip()方法默認值爲0
> ```
>
> 因此咱們在實現分頁的時候就能夠用limit來限制每頁多少條數據(通常固定一個值),用skip來決定顯示第幾頁(一個有規律變更的值)
>
> # 排序
> 在mongodb中使用使用`sort()`方法對數據進行排序,`sort()`方法能夠經過參數指定排序的字段,並使用1和-1來指定排序的方式,其中1爲升序排列,而-1是用於降序排列。
>
> 1 升序排列
> -1  降序排列
> ```js
> db.集合名.find().sort({鍵值(屬性值):1})
> ```
>
> 把`age`集合表從新根據`_id`主鍵進行降序排列
>
> ```js
> db.age.find().sort({
> "_id": -1
> })
> ```
>
> # Node.js鏈接
> 安裝mongodb的模塊
>
> ```js
> npm install mongodb
> ```
>
> ## 1.鏈接數據庫
> ```js
> var MongoClient = require('mongodb').MongoClient;
> //結尾是選擇數據庫名
> var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
> MongoClient.connect(DB_CONN_STR, function(err, db) {
> console.log("鏈接成功!");
> });
> ```
>
> ## 2.查詢數據
> 注意查詢回來的結果須要toArray來遍歷處理
>
> ```js
> var MongoClient = require('mongodb').MongoClient;
> var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
>
> MongoClient.connect(DB_CONN_STR, function(err, db) {
> console.log("鏈接成功!");
> //選中age集合,並用find方法把結果集拿回來進行處理
> db.collection("age").find({title: "cba"}).toArray(function(err, result) {
> if (err) {
> console.log('Error:' + err);
> return;
> }
> console.log(result);
> });
> });
> ```
>
> 通過測試,讀取大於100條的時候會出現報錯[官網解釋](https://docs.mongodb.com/manual/tutorial/iterate-a-cursor/#cursor-batches),能夠嘗試用`forEach`代替
>
> ```js
> db.collection('pokemon').find({})
> .forEach(function(item){
> console.log(item)
> })
> ```
>
> ### 查詢ID
> 查詢自動生成的`ObjectId`
>
> ```js
> var ObjectId = require('mongodb').ObjectId;
> let _id = ObjectId("5bcae50ed1f2c2f5e4e1a76a");
> db.collection('xxx').find({
> "_id": _id
> }).forEach(function (item) {
> console.log(item)
> })
> ```
>
> ## 3.插入數據
> insert函數第一個參數是須要插入的值(能夠一個也能夠多個),第二個參數是接受一個回調函數,當值插入成功後回返回插入值得一些關鍵信息,好比`_id`
>
> ```js
> var MongoClient = require('mongodb').MongoClient;
> var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
>
> MongoClient.connect(DB_CONN_STR, function(err, db) {
> console.log("鏈接成功!");
> const db = client.db("demo");
> db.collection("age").insert([
> {
> title: "插入的值A"
> }, {
> title: "插入的值B"
> }
> ], function(err, result) {
> if (err) {
> console.log('Error:' + err);
> return;
> }
> console.log(result)
> })
> });
> ```
>
> ## 4.更新數據
> 注意若是不加$set就是徹底替換原來的那份(沒有設置的屬性值將會丟失),加上$set則只是更新對應的屬性值,其他不作改變
>
> ```js
> var MongoClient = require('mongodb').MongoClient;
> var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
>
> MongoClient.connect(DB_CONN_STR, function(err, db) {
> console.log("鏈接成功!");
> db.collection("age").update({
> "_id": 1
> }, {
> $set: {
> title: "你好,世界",
> skill: "js"
> }
> }, function(err, result) {
> if (err) {
> console.log('Error:' + err);
> return;
> }
> //console.log(result);
> });
> });
> ```
>
> ## 5.刪除數據
> ```js
> var MongoClient = require('mongodb').MongoClient;
> var DB_CONN_STR = 'mongodb://localhost:27017/wscats';
>
> MongoClient.connect(DB_CONN_STR, function(err, db) {
> console.log("鏈接成功!");
> db.collection("age").remove({
> "_id": 1
> }, function(err, result) {
> if (err) {
> console.log('Error:' + err);
> return;
> }
> //console.log(result);
> //關閉數據庫
> db.close();
> });
> });
> ```
>
> ## 6.關閉數據庫
> ```js
> db.close();
> ```
>
> # 封裝自定義模塊
> 新建`mongo.js`寫入如下代碼,封裝自定義模塊,方便其餘路由複用,注意`assert`是node自帶的斷言模塊,用於測試代碼
>
> 參考
>
> * [官網API文檔](http://nodejs.cn/api/assert.html)
> * [Node.js的斷言模塊assert進行單元測試](https://www.cnblogs.com/hong7zai/p/5909914.html)
>
> ```js
> const MongoClient = require('mongodb').MongoClient;
> const assert = require('assert');
> const url = 'mongodb://localhost:27017';
> const dbName = 'shop';
> function query(callback) {
>   MongoClient.connect(url, function(err, client) {
>     assert.equal(null, err);
>     console.log("Connected successfully to server");
>     const db = client.db(dbName);
>     callback(db);
>     client.close();
>   });
> }
> module.exports = {
>   query
> }
> ```
>
> 在路由文件中引入和使用
>
> ```js
> var mongo = require('./mongo.js')
> router.post('/addproduct', function(req, res, next) {
>   mongo.query(function(db) {
>     db.collection("product").insertMany([req.body], function(err, result) {
>       console.log("Inserted 1 document into the collection");
>       res.send('respond with a resource');
>     });
>   })
> });
> ```
>
### mongoose
>
### 可視化
> * [Robo 3T](https://robomongo.org/)
> * [Studio3t](https://studio3t.com/download-thank-you/?OS=win64)




## Socket

### socket.io

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>socket.io</title>
<script src="socket.io.js" charset="utf-8"></script>
</head>
<body>
<h1>gp6 交流區</h1>
<div id="content" name="name" style="overflow-y: scroll; width: 400px; height: 300px; border: solid 1px #000"></div>
<br />
<div>
<input type="text" id="msg" style="width: 200px;">
</div>
<button id="submit">提交</button>
<script>
var socket = io.connect('http://10.9.164.98:8081');
const content = document.getElementById('content')
document.querySelector('#submit')
.addEventListener('click', function () {
var msg2 = msg.value
socket.emit('receive', msg2)
msg.value = ''
content.innerHTML += msg2 + '<br/>'
}, false)

socket.on('message', function(msg){
content.innerHTML += msg + '<br/>'
})
</script>
</body>
</html>

```
server.js

```js
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);

app.use(express.static(__dirname + '/client'))

io.on('connection', function (socket) {
setInterval(function () {
socket.emit('list', 'abc')
}, 1000)
socket.broadcast.emit('list', 'test');
socket.on('backend', (msg) => {
console.log(msg);
})

socket.on('receive', (msg) => {
socket.broadcast.emit('message', msg);
})
});

server.listen(8081, '10.9.164.98');

```
### net模塊

serverCode
```js
const net = require('net')

const server = new net.createServer()

let clients = {}
let clientName = 0

server.on('connection', (client) => {
client.name = ++clientName
clients[client.name] = client

client.on('data', (msg) => {
// console.log('客戶端傳來:' + msg);
broadcast(client, msg.toString())
})

client.on('error', (e) => {
console.log('client error' + e);
client.end()
})

client.on('close', (data) => {
delete clients[client.name]
console.log(client.name + ' 下線了');
})
})

function broadcast(client, msg) {
for (var key in clients) {
clients[key].write(client.name + ' 說:' + msg)
}
}

server.listen(9000)
```
clientCode

```js
var net = require('net')
const readline = require('readline')

var port = 9000
var host = '127.0.0.1'

var socket = new net.Socket()

socket.setEncoding = 'UTF-8'

socket.connect(port, host, () => {
socket.write('hello.')
})

socket.on('data', (msg) => {
console.log(msg.toString())
say()
})

socket.on('error', function (err) {
console.log('error' + err);
})

socket.on('close', function () {
console.log('connection closeed');
})

const r1 = readline.createInterface({
input: process.stdin,
output: process.stdout
})

function say() {
r1.question('請輸入:', (inputMsg) => {
if (inputMsg != 'bye') {
socket.write(inputMsg + '\n')
} else {
socket.destroy()
r1.close()
}
})
}

```
### websocket


```js
const ws = new WebSocket('ws://localhost:8080/')

ws.onopen = () => {
ws.send('你們好')
}

ws.onmessage = (msg) => {
const content = document.getElementById('content')
content.innerHTML += msg.data + '<br/>'
}

ws.onerror = (err) => {
console.log(err);
}

ws.onclose = () => {
console.log('closed~');
}
ws.send(msg2)
```

server.js

```js
const WebSocket = require('ws')
const ws = new WebSocket.Server({ port: 8080 })

let clients = {}
let clientName = 0

ws.on('connection', (client) => {
client.name = ++clientName
clients[client.name] = client

client.on('message', (msg) => {
broadcast(client, msg)
})

client.on('close', () => {
delete clients[client.name]
console.log(client.name + ' 離開了~')
})
})

function broadcast(client, msg) {
for (var key in clients) {
clients[key].send(client.name + ' 說:' + msg)
}
}

```

## SSR 與 SEO

vue 和 react 介紹


## 項目實戰

### api接口

* RestfulApi 規範
* 接口文檔的生成(apidoc)
* 接口請求方式區別

### 跨域解決

* cors
* jsonp
* proxy

### 身份驗證

#### JWT

#### Cookia+Session

### 圖片上傳
1. 安裝multer模塊
```javascript
npm install multer
```

2. 引用模塊
它是依賴於express的一個模塊
```javascript
//引用express並配置
var express = require("express");
var app = express();
app.listen(3000);
```
```javascript
var multer = require('multer');
/*var upload = multer({
  //若是用這種方法上傳,要手動添加文明名後綴
//若是用下面配置的代碼,則能夠省略這一句
  dest: 'uploads/'
})*/
```

3. 配置
設置保存文件的地方,並根據上傳的文件名對應文件添加後綴
能夠經過`filename`屬性定製文件保存的格式

|屬性值|用途|
|-|-|
|`destination`|設置資源的保存路徑。注意,若是沒有這個配置項,默認會保存在`/tmp/uploads`下。此外,路徑須要本身建立|
|`filename`|設置資源保存在本地的文件名|

```javascript
var storage = multer.diskStorage({
  //設置上傳後文件路徑,uploads文件夾會自動建立。
  destination: function(req, file, cb) {
    cb(null, './uploads')
  },
  //給上傳文件重命名,獲取添加後綴名
  filename: function(req, file, cb) {
    var fileFormat = (file.originalname).split(".");
    //給圖片加上時間戳格式防止重名名
    //好比把 abc.jpg圖片切割爲數組[abc,jpg],而後用數組長度-1來獲取後綴名
    cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
  }
});
var upload = multer({
  storage: storage
});
```

4. 接受文件
`upload.single('xxx')`,xxx與表單中的name屬性的值對應
這裏雖然用到post請求,但實際上不須要`bodyParser`模塊處理
```javascript
app.post('/upload-single', upload.single('logo'), function(req, res, next) {
  console.log(req.file)
  console.log('文件類型:%s', req.file.mimetype);
  console.log('原始文件名:%s', req.file.originalname);
  console.log((req.file.originalname).split("."))
  console.log('文件大小:%s', req.file.size);
  console.log('文件保存路徑:%s', req.file.path);
  res.send({
    ret_code: '0'
  });
});
```

5. 多圖上傳
多圖上傳只要更改一下地方,前端往file輸入框加多一個`multiple="multiple"`屬性值,此時就能夠在選圖的時候多選了,固然也能夠並列多個file輸入框(不推薦多個上傳圖片輸入框),這樣體驗會很差
```html
<input type="file" name="logo" multiple="multiple" />
```
後端也須要相應的改變
```javascript
app.post('/upload-single', upload.single('logo'), function(req, res, next) {
//upload.single('logo')變爲upload.array('logo', 2),數字表明能夠接受多少張圖片
app.post('/upload-single', upload.array('logo', 2), function(req, res, next) {
```
若是不想有圖片數量上傳限制,咱們能夠用`upload.any()`方法
```javascript
app.post('/upload-single', upload.any(), function(req, res, next) { 
  res.append("Access-Control-Allow-Origin","*");
  res.send({
    wscats_code: '0'
  });
});
```

6. 前端部分
- formData表單提交
```html
<form action="http://localhost:3000/upload-single" method="post" enctype="multipart/form-data">
  <h2>單圖上傳</h2>
  <input type="file" name="logo">
  <input type="submit" value="提交">
</form>
```

- formData表單+ajax提交
```javascript
<form id="uploadForm">
  <p>指定文件名: <input type="text" name="filename" value="" /></p>
  <p>上傳文件: <input type="file" name="logo" /></ p>
  <input type="button" value="上傳" onclick="doUpload()" />
</form>
```
`FormData`對象,是可使用一系列的鍵值對來模擬一個完整的表單,而後使用`XMLHttpRequest`發送這個"表單"

**注意點**

- processData設置爲false。由於data值是FormData對象,不須要對數據作處理。
- `<form>`標籤添加`enctype="multipart/form-data"`屬性。
- cache設置爲false,上傳文件不須要緩存。
- contentType設置爲false。由於是由`<form>`表單構造的FormData對象,且已經聲明瞭屬性`enctype="multipart/form-data"`,因此這裏設置爲false

上傳後,服務器端代碼須要使用從查詢參數名爲logo獲取文件輸入流對象,由於`<input>`中聲明的是`name="logo"`

```javascript
function doUpload() {
  $.ajax({
    url: 'http://localhost:3000/upload-single',
    type: 'POST',
    cache: false, //沒必要須
    data: new FormData($('#uploadForm')[0]),
    processData: false,//必須
    contentType: false,//必須
    success: function(data) {
      console.log(data)
    }
  })
}
```

> 參考文檔
[Github MyDemo](https://github.com/Wscats/node-tutorial/tree/master/uploadFiles)
[Github Multer](https://github.com/expressjs/multer)
[MDN FormData對象的使用](https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects)

## 自動化測試 mocha
Mocha('摩卡'),誕生於2011年,如今比較流行的JavaSscript測試框架之一,能夠運行於Node環境和瀏覽器環境

測試框架:能夠運行測試的工具。經過他,能夠爲JavaScript應用 添加測試,從而保證代碼質量
> 參考文檔
[mochajs](https://mochajs.org/)
[mocha中文文檔](https://segmentfault.com/a/1190000011362879)
### 安裝配置

使用npm 全局安裝

```
$ npm install --global mocha
```

項目依賴 局部安裝

```
$ npm isntall mocha
```
### 基本語法

### assert 斷言

+ 斷言庫:chai
+ should 風格斷言
+ expect 風格斷言

全局安裝chai

```js
npm install chai -g
```

### 案例使用

遞歸執行

```
$ mocha test --recursive
```
相關文章
相關標籤/搜索