客
戶端的JavaScript是怎樣的
? ? ? 什么是JavaScript??
+是一個(gè)腳本語言? 運(yùn)行在瀏覽器(瀏覽器的js解析內(nèi)核 v8) 實(shí)現(xiàn)用戶的交互 (interactive)
? ? ? ? ?變量? 賦值 循環(huán) 邏輯? 判斷 分支? 對象 函數(shù) 等
dom操作
bom操作
ajax
JavaScript的運(yùn)行環(huán)境?? +瀏覽器內(nèi)核解析內(nèi)核 es6
瀏覽器上的JavaScript不可以做什么谐鼎?
(不安全)+可以訪問數(shù)據(jù)庫 +不能對文件進(jìn)行操作 + 對os進(jìn)行操作 原因是不安全和瀏覽器運(yùn)行機(jī)制有關(guān)
在開發(fā)人員能力相同的情況下編程語言的能力取決于什么舰蟆?
語言本身?
? +語言本身只是提供定義變量狸棍,定義函數(shù)身害,定義類型,流程控制草戈,循環(huán)結(jié)構(gòu)之類的操作
? +取決于運(yùn)行該語言的平臺(tái)(環(huán)境)
? +對于JS來說塌鸯,我們常說JS實(shí)際是ES,大部分能力都是由瀏覽器的執(zhí)行引擎決定
為什么是JavaScript
node.js不是因?yàn)閖s產(chǎn)生的
node選擇了js
Ryan dahl
2009 2月份node有想法
2009 5月份 githup開源
2009 11月份 jsconf 講解推廣node
2010年底被xxx公司收購
2018發(fā)布有重大bug
npm
githup 世界上最大的同性交友網(wǎng)站 碼云
What is node?
? ? Node.js是一個(gè)基于Chrome V8 引擎的JavaScript運(yùn)行環(huán)境
? ? Node.js使用了一個(gè)事件驅(qū)動(dòng)唐片、非阻塞式i/o的模型丙猬,使其輕量又高效
? ? Node.js的包管理工具npm,是全球最大的開源庫生態(tài)系統(tǒng)?
? ? 官網(wǎng)? http://nodejs.cn/
? ? npm 插件官網(wǎng) :https//www.npmjs.com/
環(huán)境配置? ??
·Node的安裝
? ? 安裝包安裝
? ??????官網(wǎng)下載對應(yīng)的安裝包
????????一路next
nvm安裝(有一個(gè)類似的工具:n)
? ??????Node Version Manager(Node版本管理工具)
????????由于以后的開發(fā)工作可能會(huì)在多個(gè)Node版本中測試,而且Node的版本也比較多费韭,所以需要這么款工具來管理
下載地址
? ??????基本命令
????????nvm -v 查看版本號
????????nvm list 查看列表
????????nvm install 版本號? 安裝node
????????nvm uninstall 版本號? 卸載node
相關(guān)版本
????????????node版本常識(shí)
????????????????????偶數(shù)版本為穩(wěn)定版 (0.6.x 淮悼,0.8.x ,0.10.x)
????????????????????奇數(shù)版本為非穩(wěn)定版(0.7.x 揽思,0.9.x ,0.11.x)
????????????????????LTS(Long Term Support)
????????????????????LTS和Current區(qū)別
????????????操作方式:
????????????????????重新下載最新的安裝包见擦;
????????????????????覆蓋安裝即可钉汗;
????????????問題:
????????????????????以前版本安裝的很多全局的工具包需要重新安裝
????????????????????無法回滾到之前的版本
????????????????????無法在多個(gè)版本之間切換(很多時(shí)候我們要使用特定版本)
Windows下常用的命令行操作
????????????切換當(dāng)前目錄(change directory):cd
????????????創(chuàng)建目錄(make directory):mkdir
????????????查看當(dāng)前目錄列表(directory):dir
????????????別名:ls(list)
????????????清空當(dāng)前控制臺(tái):cls
????????????別名:clear
????????????刪除文件:del
????????????別名:rm
注意:所有別名必須在新版本的 PowerShell (linux系統(tǒng))中使用
常見問題
????????Python環(huán)境丟失
? ? ? ? Node中有些第三方的包是以C/C++源碼的方式發(fā)布的,需要安裝后編譯,確保全局環(huán)境中可以使用python命令,python 版本推薦2.7.0
? ? ? ? ?環(huán)境變量丟失
????????部分電腦安裝完畢之后沒有環(huán)境變量需要手動(dòng)配置
? ? ? ? ?Windows中環(huán)境變量分為系統(tǒng)變量和用戶變量
? ? ? ? ?環(huán)境變量的變量名是不區(qū)分大小寫的
? ? ? ? ?PATH 變量:只要添加到 PATH 變量中的路徑鲤屡,都可以在任何目錄下
? ? ? ? 目的可以在任何地方調(diào)起node命令
##模塊,包 commonjs
commonjs規(guī)范
前端模塊化:AMD,CMD,Commnjs
Node 應(yīng)用由模塊化組成损痰,采用CommonJS模塊規(guī)范
定義 module
每個(gè)文件就是一個(gè)模塊,有自己的作用域酒来。在一個(gè)文件夾里面定義的變量卢未、函數(shù)、類,都 是私有的辽社,對其它模塊文件不可見伟墙。
暴露接口
CommonJS規(guī)范規(guī)定,每個(gè)模塊內(nèi)部滴铅,module變量代表當(dāng)前模塊戳葵。這個(gè)變量是一個(gè)對象 ,它的exports屬性(即module.exports)是對外的接口汉匙。加載某個(gè)模塊拱烁,其實(shí)是加載該模塊的module.exports屬性。
引用
require方法用于加載模塊
var example = require('./expample.js');
console.log(example.x);//5
console.log(example.addx(1))//6
模塊的分類
內(nèi)置模塊
? ? const process = require('process');
? ? const path=? require('path')
自定義模塊
? ? 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入門
?官網(wǎng):https://www.npmjs.com/
安裝:無需安裝
查看當(dāng)前版本
? ? $ npm -v
更新?
? ?$? npm init
? ? $ npm init --yes? 默認(rèn)配置
安裝包
使用npm.install會(huì)讀取package.json文件來安裝模塊噩翠。安裝的模塊分為兩類 dependencies和devDependencies ,分別對應(yīng)生產(chǎn)環(huán)境需要的安裝包和開發(fā)環(huán)境 需要的安裝包
$ 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源
????????臨時(shí)使用, 安裝包的時(shí)候通過--registry參數(shù)即可
????????$ npm install express --registry?https://registry.npm.taobao.org
????????全局使用
????????????????? $ npm config set registry https://registry.npm.taobao.org
????????????????? // 配置后可通過下面方式來驗(yàn)證是否成功
????????????????? npm config get registry
????????????????? // 或
????????????????? npm info express
????????cnpm 使用
????????????????// 安裝cnpm
????????????????? npm install -g cnpm --registry=https://registry.npm.taobao.org
????????????????? // 使用cnpm安裝包
?????????????????cnpm install express
常用的內(nèi)置模塊
node 常用內(nèi)置api
(1) URL 網(wǎng)址解析 解析URL相關(guān)網(wǎng)址信息 url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) url.format(urlObject) url.resolve(from, to) (2) QueryString 參數(shù)處理 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 方法
2戏自、Node.js 基礎(chǔ)應(yīng)用 1、應(yīng)用 HTTP 模塊編寫一個(gè)小爬蟲工具 (1) 利用爬蟲獲取“拉勾網(wǎng)”首頁列表數(shù)據(jù) (2) 通過 npm 安裝 cheerio 模塊獲得數(shù)據(jù) 2伤锚、后端表單的提交 要求: (1) 應(yīng)用 request post 模擬提交表單
文件讀取
Node中文件讀取的方式主要 有:
fs.readFile('url','utf-8',(err,data)=>{
? ? if(err) throw err
? ? console.log(data)
})
fs.readFileSync(file[, options])
try{constdata=fs.readFileSync('c:\\demo\1.txt','utf8');console.log(data);}catch(e){// 文件不存在擅笔,或者權(quán)限錯(cuò)誤throwe;}
fs.createReadStream(path[, options])
conststream=fs.createReadStream('c:\\demo\1.txt');letdata=''stream.on('data',(trunk)=>{data+=trunk;});stream.on('end',()=>{console.log(data);});
由于Windows平臺(tái)下默認(rèn)文件編碼是GBK,在Node中不支持见芹,可以通過iconv-lite解決
constreadline=require('readline');constfs=require('fs');constrl=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))
fs.writeFile('c:\\demo\a.txt',newDate(),(error)=>{console.log(error);});
fs.writeFileSync(file, data[, options])
try{fs.writeFileSync('c:\\demo\a.txt',newDate());}catch(error){// 文件夾不存在剂娄,或者權(quán)限錯(cuò)誤console.log(error);}
fs.createWriteStream(path[,option])
varstreamWriter=fs.createWriteStream('c:\\demo\a.txt');setInterval(()=>{streamWriter.write(`${newDate}\n`,(error)=>{console.log(error);});},1000);
###node中的異步操作
fs模塊對文件的幾乎所有操作都有同步和異步兩種形式
例如:readFile() 和 readFileSync()
區(qū)別:
同步調(diào)用會(huì)阻塞代碼的執(zhí)行,異步則不會(huì)
異步調(diào)用會(huì)將讀取任務(wù)下達(dá)到任務(wù)隊(duì)列玄呛,直到任務(wù)執(zhí)行完成才會(huì)回調(diào)
異常處理方面阅懦,同步必須使用 try catch 方式,異步可以通過回調(diào)函數(shù)的第一個(gè)參數(shù)
console.time('sync');try{vardata=fs.readFileSync(path.join('C:\\Users\\iceStone\\Downloads','H.mp4'));// console.log(data);}catch(error){throwerror;}console.timeEnd('sync');console.time('async');fs.readFile(path.join('C:\\Users\\iceStone\\Downloads','H.mp4'),(error,data)=>{if(error)throwerror;// console.log(data);});console.timeEnd('async');
what is Promise * Promise是抽象異步處理對象以及對其進(jìn)行各種操作的組件徘铝。Promise并不是從JavaScript中發(fā)祥的概念耳胎。 Promise最初被提出是在 E語言中, 它是基于并列/并行處理設(shè)計(jì)的一種編程語言惕它。 現(xiàn)在JavaScript也擁有了這種特性怕午,這就是JavaScript Promise
使用了回調(diào)函數(shù)的異步處理
----getAsync("fileA.txt",function(error,result){if(error){// 取得失敗時(shí)的處理throwerror;}// 取得成功時(shí)的處理});----<1>傳給回調(diào)函數(shù)的參數(shù)為(error對象,執(zhí)行結(jié)果)錯(cuò)誤優(yōu)先處理
使用了回調(diào)函數(shù)的異步處理
----varpromise=getAsyncPromise("fileA.txt");promise.then(function(result){// 獲取文件內(nèi)容成功時(shí)的處理}).catch(function(error){// 獲取文件內(nèi)容失敗時(shí)的處理});----<1>返回promise對象
創(chuàng)建Promise對象 *
var promise = new Promise(function(resolve, reject) {
? ? // 異步處理
? ? // 處理結(jié)束后淹魄、調(diào)用resolve 或 reject
? ? resolve('成功處理')
? ? reject('錯(cuò)誤處理')
});
使用實(shí)例 *
創(chuàng)建一個(gè)priomise 對象并返回new Promise(fn)
在fn 中指定異步等處理
處理結(jié)果正常的話郁惜,調(diào)用resolve(處理結(jié)果值)
處理結(jié)果錯(cuò)誤的話,調(diào)用?reject(Error對象)
functionasyncFunction(){returnnewPromise(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的狀態(tài)
用new Promise 實(shí)例化的promise對象有以下三個(gè)狀態(tài)甲锡。
"has-resolution" - Fulfilled?resolve(成功)時(shí)兆蕉。
"has-rejection" - Rejected?reject(失敗)時(shí)
"unresolved" - Pending?既不是resolve也不是reject的狀態(tài)。也就是promise對象剛被創(chuàng)建后的初始化狀態(tài)等
promise對象的狀態(tài)缤沦,從Pending轉(zhuǎn)換為Fulfilled或Rejected之后虎韵, 這個(gè)promise對象的狀態(tài)就不會(huì)再發(fā)生任何變化。
也就是說缸废,Promise與Event等不同包蓝,在.then 后執(zhí)行的函數(shù)可以肯定地說只會(huì)被調(diào)用一次驶社。
另外,F(xiàn)ulfilled和Rejected這兩個(gè)中的任一狀態(tài)都可以表示為Settled(不變的)测萎。
Settled resolve(成功) 或 reject(失敗)亡电。
從Pending和Settled的對稱關(guān)系來看,Promise狀態(tài)的種類/遷移是非常簡單易懂的绳泉。
當(dāng)promise的對象狀態(tài)發(fā)生變化時(shí)逊抡,用.then 來定義只會(huì)被調(diào)用一次的函數(shù)。
在文件操作的過程中零酪,都必須使用物理路徑(絕對路徑)冒嫡,path模塊提供了一系列與路徑相關(guān)的 API
console.log('join用于拼接多個(gè)路徑部分,并轉(zhuǎn)化為正常格式');consttemp=path.join(__dirname,'..','lyrics','./友誼之光.lrc');console.log(temp);console.log('獲取路徑中的文件名');console.log(path.basename(temp));console.log('獲取路徑中的文件名并排除擴(kuò)展名');console.log(path.basename(temp,'.lrc'));console.log('====================================');console.log('獲取不同操作系統(tǒng)的路徑分隔符');console.log(process.platform+'的分隔符為 '+path.delimiter);console.log('一般用于分割環(huán)境變量');console.log(process.env.PATH.split(path.delimiter));console.log('====================================');console.log('獲取一個(gè)路徑中的目錄部分');console.log(path.dirname(temp));console.log('====================================');console.log('獲取一個(gè)路徑中最后的擴(kuò)展名');console.log(path.extname(temp));console.log('====================================');console.log('將一個(gè)路徑解析成一個(gè)對象的形式');constpathObject=path.parse(temp);console.log(pathObject);console.log('====================================');console.log('將一個(gè)路徑對象再轉(zhuǎn)換為一個(gè)字符串的形式');// pathObject.name = '我終于失去了你';pathObject.base='我終于失去了你.lrc';console.log(pathObject);console.log(path.format(pathObject));console.log('====================================');console.log('獲取一個(gè)路徑是不是絕對路徑');console.log(path.isAbsolute(temp));console.log(path.isAbsolute('../lyrics/愛的代價(jià).lrc'));console.log('====================================');console.log('將一個(gè)路徑轉(zhuǎn)換為當(dāng)前系統(tǒng)默認(rèn)的標(biāo)準(zhǔn)格式四苇,并解析其中的./和../');console.log(path.normalize('c:/develop/demo\\hello/../world/./a.txt'));console.log('====================================');console.log('獲取第二個(gè)路徑相對第一個(gè)路徑的相對路徑');console.log(path.relative(__dirname,temp));console.log('====================================');console.log('以類似命令行cd命令的方式拼接路徑');console.log(path.resolve(temp,'c:/','./develop','../application'));console.log('====================================');console.log('獲取不同平臺(tái)中路徑的分隔符(默認(rèn))');console.log(path.sep);console.log('====================================');console.log('允許在任意平臺(tái)下以WIN32的方法調(diào)用PATH對象');// console.log(path.win32);console.log(path===path.win32);console.log('====================================');console.log('允許在任意平臺(tái)下以POSIX的方法調(diào)用PATH對象');console.log(path===path.posix);
官網(wǎng):http://www.expressjs.com.cn/
安裝
$ npm install express --save
快速開始
constexpress=require('express')constapp=express()app.get('/',(req,res)=>res.send('Hello World!'))app.listen(3000,()=>console.log('Example app listening on port 3000!'))
letexpress=require('express')letrouter=express.Router()// 該路由使用的中間件router.use((req,res,next)=>{next()});// 定義網(wǎng)站主頁的路由router.post('/addFood',function(req,res){console.log('hahaha')// res.send('這里是admin的登錄');});// 定義 about 頁面的路由router.post('/regist',function(req,res){res.send('這里是admin的注冊側(cè)');});module.exports=router;app.use('/admin',admin)
get
req.query
post
req.body
body-parser
設(shè)置中文格式
res.set('Content-Type','text/plain,charset=utf8')
app.use(express.static('public'))app.use('/static',express.static('public'))app.use('/static',express.static(path.join(__dirname,'public')))
在Mongodb官網(wǎng)下載最新版本的Mongodb下載地址
下載msi的window安裝包孝凌,可以裝到C盤或者D盤目錄下
由于我是安裝在D盤的環(huán)境下
D:\Program Files (x86)\MongoDB\Server\3.2\bin
所以在bin文件夾下找到mongod.exe命令,然后通過管理員執(zhí)行mongod --dbpath x路徑x月腋,路徑可以是任何地方蟀架,我這里選擇在D盤的MongoDB目錄下,當(dāng)然路徑不要包含特殊的字符串榆骚,比如Program Files (x86)也不行
mongod --dbpath D:\mongodb\data\db
經(jīng)過上面的配置之后片拍,就可以返回bin目錄下找到mongo.exe命令,并管理員下執(zhí)行妓肢,就可以出現(xiàn)mongodb的命令行模式
D:\Program Files (x86)\MongoDB\Server\3.2\bin
然后就可以使用下面的命令來測試了
db.help()//幫助db.stats()//統(tǒng)計(jì)
showdbs
檢查當(dāng)前選擇的數(shù)據(jù)庫
db
數(shù)據(jù)庫名為數(shù)據(jù)庫創(chuàng)建的名字捌省,使用該命令后會(huì)默認(rèn)切換到對應(yīng)的數(shù)據(jù)庫,并且在數(shù)據(jù)庫中添加選項(xiàng)碉钠,數(shù)據(jù)庫信息才顯示纲缓,如果默認(rèn)就有該數(shù)據(jù)庫,那就是切換到對應(yīng)的數(shù)據(jù)庫里面
use數(shù)據(jù)庫名
先切換到對應(yīng)的數(shù)據(jù)庫喊废,然后再執(zhí)行db.dropDatabase()刪除該數(shù)據(jù)庫
use數(shù)據(jù)庫名//switched to db 數(shù)據(jù)庫名db.dropDatabase()
用一下命令可以檢查創(chuàng)建的集合
showcollections
在創(chuàng)建完數(shù)據(jù)庫之后祝高,我們就可以創(chuàng)建集合
db.createCollection(集合名字name,設(shè)置參數(shù)options[對象類型])
name是要?jiǎng)?chuàng)建的集合的名稱污筷。?options是一個(gè)文檔工闺,用于指定集合的配置
參數(shù) 類型 描述 name String 要?jiǎng)?chuàng)建的集合的名稱 options Document (可選)指定有關(guān)內(nèi)存大小和索引的選項(xiàng)?options參數(shù)是可選的,因此只需要指定集合的名稱瓣蛀。 以下是可以使用的選項(xiàng)列表:
字段 類型 描述 capped Boolean (可選)如果為true陆蟆,則啟用封閉的集合。上限集合是固定大小的集合揪惦,它在達(dá)到其最大大小時(shí)自動(dòng)覆蓋其最舊的條目。 如果指定true罗侯,則還需要指定size參數(shù)器腋。 autoIndexId Boolean (可選)如果為true,則在_id字段上自動(dòng)創(chuàng)建索引。默認(rèn)值為false纫塌。 size 數(shù)字 (可選)指定上限集合的最大大小(以字節(jié)為單位)诊县。 如果capped為true,那么還需要指定此字段的值措左。 max 數(shù)字 (可選)指定上限集合中允許的最大文檔數(shù)依痊。 由于option是可選,我們也可以不帶配置項(xiàng)創(chuàng)建集合
db.createCollection("mycollection")
db.collection.drop()用于從數(shù)據(jù)庫中刪除集合
db.集合名.drop()
比如我們可以測試以下操作
db.createCollection("wscats")//創(chuàng)建名為wscats的集合showcollections//顯示該數(shù)據(jù)庫所有集合? wscatsdb.wscats.drop()//刪除名為wscats的集合
最簡單查看文檔的方法就是find()怎披,會(huì)檢索集合中所有的文檔結(jié)果
db.集合名.find()
要以格式化的方式顯示結(jié)果胸嘁,可以使用pretty()方法。
db.集合名.find().pretty()
尋找age集合里面所有含有屬性值為wscats的文檔結(jié)果凉逛,相當(dāng)于where name = 'wscats'
db.age.find({name:"wscats"})
操作 語法 示例 等效語句 相等 {:}?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
在find()方法中性宏,如果通過使用,將它們分開傳遞多個(gè)鍵状飞,則mongodb將其視為AND條件毫胜。 以下是AND的基本語法
尋找_id為1并且name為wscats的所有結(jié)果集
db.age.find({$and:[{"_id":1},{"name":"wscats"}]})
在要根據(jù)OR條件查詢文檔,需要使用$or關(guān)鍵字诬辈。以下是OR條件的基本語法
尋找name為corrine或者name為wscats的所有結(jié)果集
db.age.find({$or:[{"name":"corrine"},{“name“:"wscats"}]})
相當(dāng)于語句where title = "wscats" OR ( title = "corrine" AND _id < 5)
db.age.find({$or:[{"title":"wscats"},{$and:[{"title":"corrine"},{"_id":{$lte:5}}]}]})
文檔的數(shù)據(jù)結(jié)構(gòu)和JSON基本一樣酵使。 所有存儲(chǔ)在集合中的數(shù)據(jù)都是BSON格式。 BSON是一種類json的一種二進(jìn)制形式的存儲(chǔ)格式,簡稱Binary JSON焙糟。
要將數(shù)據(jù)插入到mongodb集合中口渔,需要使用mongodb的insert()或save()方法。
db.集合名.insert(document)
比如我們可以插入以下數(shù)據(jù)
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,})
也可以支持插入多個(gè)酬荞,注意傳入的是數(shù)組形式
db.wscats.insert([{_id:100,title:‘Hello’},{_id:101,title:‘World’}])
在插入的文檔中搓劫,如果不指定_id參數(shù),那么mongodb會(huì)為此文檔分配一個(gè)唯一的ObjectId 要插入文檔混巧,也可以使用db.post.save(document)枪向。如果不在文檔中指定_id,那么save()方法將與insert()方法一樣自動(dòng)分配ID的值咧党。如果指定_id秘蛔,則將以save()方法的形式替換包含**_id**的文檔的全部數(shù)據(jù)。
db.wscats.save({_id:111,title:'Oaoafly Wscats',})
尋找第一條title為wscats的值傍衡,并且更新值title為corrine和age為12
db.age.update({'title':'wscats'},{$set:{'title':'corrine','age':12}})
默認(rèn)情況下深员,mongodb只會(huì)更新一個(gè)文檔。要更新多個(gè)文檔蛙埂,需要將參數(shù)multi設(shè)置為true倦畅,還可以配合find方法里面的各種復(fù)雜條件判斷來篩選結(jié)果,然后更新多個(gè)文檔
尋找所有title為wscats的值绣的,并且更新值title為corrine和age為12
db.age.update({'title':'wscats'},{$set:{'title':'corrine','age':12}},{multi:true})
將_id主鍵為3的文檔叠赐,覆蓋新的值欲账,注意_id為必傳
db.age.save({
? '_id':3,
? 'title': 'wscats'
})
刪除主鍵_id為3的文檔,默認(rèn)是刪除多條
db.age.remove({'_id':3})
建議在執(zhí)行remove()函數(shù)前先執(zhí)行find()命令來判斷執(zhí)行的條件是否正確
如果你只想刪除第一條找到的記錄可以設(shè)置justOne為1芭概,如下所示
db.age.remove({...},1)
全部刪除
db.age.remove({})
如果你需要在mongodb中讀取指定數(shù)量的數(shù)據(jù)記錄赛不,可以使用mongodb的Limit方法,limit()方法接受一個(gè)數(shù)字參數(shù)罢洲,該參數(shù)指定從mongodb中讀取的記錄條數(shù)踢故。
db.age.find().limit(數(shù)量)
我們除了可以使用limit()方法來讀取指定數(shù)量的數(shù)據(jù)外,還可以使用skip()方法來跳過指定數(shù)量的數(shù)據(jù)惹苗,skip方法同樣接受一個(gè)數(shù)字參數(shù)作為跳過的記錄條數(shù)殿较。
db.age.find().limit(數(shù)量).skip(數(shù)量)//skip()方法默認(rèn)值為0
所以我們在實(shí)現(xiàn)分頁的時(shí)候就可以用limit來限制每頁多少條數(shù)據(jù)(一般固定一個(gè)值),用skip來決定顯示第幾頁(一個(gè)有規(guī)律變動(dòng)的值)
在mongodb中使用使用sort()方法對數(shù)據(jù)進(jìn)行排序鸽粉,sort()方法可以通過參數(shù)指定排序的字段斜脂,并使用1和-1來指定排序的方式,其中1為升序排列触机,而-1是用于降序排列帚戳。
1 升序排列 -1 降序排列
db.集合名.find().sort({鍵值(屬性值):1})
把a(bǔ)ge集合表重新根據(jù)_id主鍵進(jìn)行降序排列
db.age.find().sort({"_id":-1})
安裝mongodb的模塊
npminstallmongodb
varMongoClient=require('mongodb').MongoClient;//結(jié)尾是選擇數(shù)據(jù)庫名varDB_CONN_STR='mongodb://localhost:27017/wscats';MongoClient.connect(DB_CONN_STR,function(err,db){console.log("連接成功!");});
注意查詢回來的結(jié)果需要toArray來遍歷處理
varMongoClient=require('mongodb').MongoClient;varDB_CONN_STR='mongodb://localhost:27017/wscats';MongoClient.connect(DB_CONN_STR,function(err,db){console.log("連接成功儡首!");//選中age集合片任,并用find方法把結(jié)果集拿回來進(jìn)行處理db.collection("age").find({title:"cba"}).toArray(function(err,result){if(err){console.log('Error:'+err);return;}console.log(result);});});
經(jīng)過測試,讀取大于100條的時(shí)候會(huì)出現(xiàn)報(bào)錯(cuò)官網(wǎng)解釋蔬胯,可以嘗試用forEach代替
db.collection('pokemon').find({}).forEach(function(item){console.log(item)})
查詢自動(dòng)生成的ObjectId
varObjectId=require('mongodb').ObjectId;let_id=ObjectId("5bcae50ed1f2c2f5e4e1a76a");db.collection('xxx').find({"_id":_id}).forEach(function(item){console.log(item)})
insert函數(shù)第一個(gè)參數(shù)是需要插入的值(可以一個(gè)也可以多個(gè))对供,第二個(gè)參數(shù)是接受一個(gè)回調(diào)函數(shù),當(dāng)值插入成功后回返回插入值得一些關(guān)鍵信息氛濒,比如_id
varMongoClient=require('mongodb').MongoClient;varDB_CONN_STR='mongodb://localhost:27017/wscats';MongoClient.connect(DB_CONN_STR,function(err,db){console.log("連接成功产场!");constdb=client.db("demo");db.collection("age").insert([{title:"插入的值A(chǔ)"},{title:"插入的值B"}],function(err,result){if(err){console.log('Error:'+err);return;}console.log(result)})});
注意如果不加$set就是完全替換原來的那份(沒有設(shè)置的屬性值將會(huì)丟失),加上$set則只是更新對應(yīng)的屬性值舞竿,其余不做改變
varMongoClient=require('mongodb').MongoClient;varDB_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);});});
varMongoClient=require('mongodb').MongoClient;varDB_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);//關(guān)閉數(shù)據(jù)庫db.close();});});
db.close();
新建mongo.js寫入以下代碼确徙,封裝自定義模塊,方便其他路由復(fù)用执桌,注意assert是node自帶的斷言模塊鄙皇,用于測試代碼
參考
constMongoClient=require('mongodb').MongoClient;constassert=require('assert');consturl='mongodb://localhost:27017';constdbName='shop';functionquery(callback){MongoClient.connect(url,function(err,client){assert.equal(null,err);console.log("Connected successfully to server");constdb=client.db(dbName);callback(db);client.close();});}module.exports={query}
在路由文件中引入和使用
varmongo=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');});})});
<div><inputtype="text"id="msg"style="width: 200px;"></div><buttonid="submit">提交</button><script>varsocket=io.connect('http://10.9.164.98:8081');constcontent=document.getElementById('content')document.querySelector('#submit').addEventListener('click',function(){varmsg2=msg.valuesocket.emit('receive',msg2)msg.value=''content.innerHTML+=msg2+'<br/>'},false)socket.on('message',function(msg){content.innerHTML+=msg+'<br/>'})</script></body></html>
server.js
varexpress=require('express');varapp=express();varserver=require('http').Server(app);vario=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');
serverCode
constnet=require('net')constserver=newnet.createServer()letclients={}letclientName=0server.on('connection',(client)=>{client.name=++clientNameclients[client.name]=clientclient.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)=>{deleteclients[client.name]console.log(client.name+' 下線了');})})functionbroadcast(client,msg){for(varkeyinclients){clients[key].write(client.name+' 說:'+msg)}}server.listen(9000)
clientCode
varnet=require('net')constreadline=require('readline')varport=9000varhost='127.0.0.1'varsocket=newnet.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');})constr1=readline.createInterface({input:process.stdin,output:process.stdout})functionsay(){r1.question('請輸入:',(inputMsg)=>{if(inputMsg!='bye'){socket.write(inputMsg+'\n')}else{socket.destroy()r1.close()}})}
constws=newWebSocket('ws://localhost:8080/')ws.onopen=()=>{ws.send('大家好')}ws.onmessage=(msg)=>{constcontent=document.getElementById('content')content.innerHTML+=msg.data+'<br/>'}ws.onerror=(err)=>{console.log(err);}ws.onclose=()=>{console.log('closed~');}ws.send(msg2)
server.js
constWebSocket=require('ws')constws=newWebSocket.Server({port:8080})letclients={}letclientName=0ws.on('connection',(client)=>{client.name=++clientNameclients[client.name]=clientclient.on('message',(msg)=>{broadcast(client,msg)})client.on('close',()=>{deleteclients[client.name]console.log(client.name+' 離開了~')})})functionbroadcast(client,msg){for(varkeyinclients){clients[key].send(client.name+' 說:'+msg)}}
RestfulApi 規(guī)范
接口文檔的生成(apidoc)
接口請求方式區(qū)別
cors
jsonp
proxy
產(chǎn)生token
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
驗(yàn)證token
// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
? console.log(decoded.foo) // bar
});
npm install express-session -d --save
app.use(session({
? secret: "weird sheep",
? resave: false,
? saveUninitialized: true,
? cookie: {user:"default",maxAge: 14*24*60*60*1000}
}));
session存值
req.session.user = user;
req.session.isLogin = true;
?
安裝multer模塊
npminstallmulter
引用模塊 它是依賴于express的一個(gè)模塊
//引用express并配置varexpress=require("express");varapp=express();app.listen(3000);
varmulter=require('multer');/*var upload = multer({ //如果用這種方法上傳,要手動(dòng)添加文明名后綴? ? ? ? //如果用下面配置的代碼仰挣,則可以省略這一句 dest: 'uploads/'})*/
配置 設(shè)置保存文件的地方伴逸,并根據(jù)上傳的文件名對應(yīng)文件添加后綴 可以通過filename屬性定制文件保存的格式
屬性值用途
destination設(shè)置資源的保存路徑。注意膘壶,如果沒有這個(gè)配置項(xiàng)错蝴,默認(rèn)會(huì)保存在/tmp/uploads下博烂。此外,路徑需要自己創(chuàng)建
filename設(shè)置資源保存在本地的文件名
varstorage=multer.diskStorage({//設(shè)置上傳后文件路徑漱竖,uploads文件夾會(huì)自動(dòng)創(chuàng)建。destination:function(req,file,cb){cb(null,'./uploads')},//給上傳文件重命名畜伐,獲取添加后綴名filename:function(req,file,cb){varfileFormat=(file.originalname).split(".");//給圖片加上時(shí)間戳格式防止重名名//比如把 abc.jpg圖片切割為數(shù)組[abc,jpg],然后用數(shù)組長度-1來獲取后綴名cb(null,file.fieldname+'-'+Date.now()+"."+fileFormat[fileFormat.length-1]);}});varupload=multer({storage:storage});
接受文件?upload.single('xxx')馍惹,xxx與表單中的name屬性的值對應(yīng) 這里雖然用到post請求,但實(shí)際上不需要bodyParser模塊處理
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'});});
多圖上傳 多圖上傳只要更改一下地方万矾,前端往file輸入框加多一個(gè)multiple="multiple"屬性值津滞,此時(shí)就可以在選圖的時(shí)候多選了格粪,當(dāng)然也可以并列多個(gè)file輸入框(不推薦多個(gè)上傳圖片輸入框)煤傍,這樣體驗(yàn)會(huì)不好
<inputtype="file"name="logo"multiple="multiple" />
后端也需要相應(yīng)的改變
app.post('/upload-single',upload.single('logo'),function(req,res,next){//upload.single('logo')變?yōu)閡pload.array('logo', 2)盟庞,數(shù)字代表可以接受多少張圖片app.post('/upload-single',upload.array('logo',2),function(req,res,next){
如果不想有圖片數(shù)量上傳限制蔚约,我們可以用upload.any()方法
app.post('/upload-single',upload.any(),function(req,res,next){res.append("Access-Control-Allow-Origin","*");res.send({wscats_code:'0'});});
前端部分
formData表單提交
<formaction="http://localhost:3000/upload-single"method="post"enctype="multipart/form-data"><h2>單圖上傳</h2><inputtype="file"name="logo"><inputtype="submit"value="提交"></form>
formData表單+ajax提交
<formid="uploadForm"><p>指定文件名:<inputtype="text"name="filename"value=""/></p><p>上傳文件:<inputtype="file"name="logo"/></p><inputtype="button"value="上傳"onclick="doUpload()"/></form>
FormData對象旺拉,是可以使用一系列的鍵值對來模擬一個(gè)完整的表單候醒,然后使用XMLHttpRequest發(fā)送這個(gè)"表單"
注意點(diǎn)
processData設(shè)置為false灭衷。因?yàn)閐ata值是FormData對象馅精,不需要對數(shù)據(jù)做處理严嗜。
<form>標(biāo)簽添加enctype="multipart/form-data"屬性。
cache設(shè)置為false洲敢,上傳文件不需要緩存漫玄。
contentType設(shè)置為false。因?yàn)槭怯?lt;form>表單構(gòu)造的FormData對象压彭,且已經(jīng)聲明了屬性enctype="multipart/form-data"睦优,所以這里設(shè)置為false
上傳后,服務(wù)器端代碼需要使用從查詢參數(shù)名為logo獲取文件輸入流對象壮不,因?yàn)?lt;input>中聲明的是name="logo"
functiondoUpload(){$.ajax({url:'http://localhost:3000/upload-single',type:'POST',cache:false,//不必須data:newFormData($('#uploadForm')[0]),processData:false,//必須contentType:false,//必須success:function(data){console.log(data)}})}