基本使用
概念
SQL和NoSQL
文件 Document
文件就是鍵值對的一個集合,實際上表達方式和JSON一樣
文件就是JSON,但是要比JSON多了一些限制:
- 每個文件必須有一個特殊的鍵 _id, 這個鍵在集合中必須是保證唯一性.
- 文件中鍵的命名,不能含有
.
和$
- 文件中值的額型別,比原生JavaScript更多, 比如:日期,ObjectId(),正規表示式
- 文件是給使用者看的,是JSON的表示模式,但實際儲存的時候,是BSON方式(用二進位制方式儲存)
集合 Collections
集合就是一組文件(document),相當於“表”
集合中可以儲存完全不同的結構的文件
資料庫 DataBase
- 資料庫中儲存眾多的集合
- 資料庫最終會變成檔案系統裡的檔案,而資料庫名字就是相應的檔名。資料庫的命名應該遵守作業系統的檔案命名規範。
- 資料庫命名不能是admin,local,config
mongod
mongo
使用資料庫
mongod
開機
mongoimport
匯入資料
mongod --dbpath c:\mongodata
// --dbpath 引數,表示資料庫的存放位置,資料夾必須事先建立
// mongoDB 有真實的物理檔案,對應一個個資料庫。
db.help(); // 在 mongodb 客戶端中獲得幫助
db.stats();
顯示資料庫名稱、集合數目,以及資料庫中的文件
MongoDB資料模型
MongoDB 中的資料模式非常靈活。同一集合中的文件不需要具有同一欄位或結構,集合文件的公用欄位可能包含不同型別的資料。
設計 MongoDB 模式注意問題
- 根據使用者需求來設計模式。
- 如果想一起使用物件,請將這些物件合併到一個文件中,否則要將它們分開(但是要確保不需要連線)。
- 經常複製資料(但要有一定限度),因為與計算時間相比,硬碟空間顯得非常便宜。
- 在寫入時進行連線,而不能在讀取時連線。
- 針對經常發生的用例來設計模式。
- 在模式中實現複雜的聚合。
- 資料庫中儲存眾多集合。
- 資料庫最終會變為檔案系統裡面的檔案,而資料庫名字就是相應的檔名,所以資料庫的命名,應該遵守作業系統的檔名命名規範。
- 資料庫命名不能是
admin
、local
、config
基本命令列操作
列出所有資料庫
show dbs;
使用某個資料庫
use students;
// 如果想新建,也是use, use一個不存在的庫名,就是建立一個資料庫。
檢視當前所在庫
db
集合沒有檢視,需要插入資料之後,能夠看到。 如果真的想建立剛才未存在的資料庫,那麼必須插入一個資料。不需要建立集合。
例如:
db.student.insert({'name': 'xiaoming', 'age': 23});
//student就是所謂的集合(collections)。集合中儲存著很多json(document)。
//db. 一個未知的集合名字,這個集合將自動建立。
mongodb增刪改查
建立資料庫
用 use + 資料庫名稱
的方式來建立資料庫。use 會建立一個新的資料庫,如果該資料庫存在,則返回這個資料庫。
use mydb
使用命令 db
檢查當前選定的資料庫。
db
使用命令 show dbs
來檢查資料庫列表。
show dbs
剛建立的資料庫(mydb)沒有出現在列表中。為了讓資料庫顯示出來,至少應該插入一個文件。
刪除資料庫
db.dropDatabase();
// 刪除當前所在的資料庫
匯入外部資料
mongoimport --db test --collection restaurants --dorp --file ddd.json
// --db test 想往那個資料庫中匯入
// --collection restaurants 想往那個集合中匯入
// --dorp 把集合清空 表示資料庫中有預設資料,覆蓋原有資料。
// --file ddd.json 使用的是哪個檔案.
mongoimport --db student --collection class1 --dorp --file a.json
建立集合(表)
db.class1
//如果集合不存在,幫你建立集合
使用 show collections 來檢視建立了的集合。
show collections
// 沒有資料,剛建立的 集合 並不顯示出來。
插入資料
db.class1.insert({'name': 'ting','age': 21});
檢視資料(文件)
db.class1.find({}); //db.class1.find();
//find() 方法會以非結構化的方式來顯示所有文件。
db.class1.find().pretty();
//用格式化方式顯示結果
//在 find() 方法中,如果傳入多個鍵,並用逗號(,)分隔它們,那麼 MongoDB 會把它看成是 AND 條件。
db.class1.find({'key1': 'val1', 'key2': 'val2'});
//若基於 OR 條件來查詢文件,可以使用關鍵字 $or。 //或 的條件
db.class1.find({$or: [{key1: val1, key2: val2}]});
排序
db.class.find().sort({'sex': 1}); //1 升序
修改資料
// update暗含查詢,修改誰,修改結果 update預設只會修改第一個document,需要第三個引數支援: {'multi': true}
db.class1.update({'name': 'xiaoming'},{$set: {'age': 16}});
// 批量修改
db.class1.update({'score.math': '60'},{$set: {'age': 20}}, {'multi': true});
db.class1.update({},{$set: {'age': 20}},{'multi': true}); //第一個引數為空,表示全部資料修改。
// 替換document, 沒有使用$set關鍵字,完整替換
db.class1.uodate({'name': 'xiaoming'},{'age': 12});
刪除資料
db.student1.drop(); // 刪除集合 (籃子都刪除)
db.studnet1.remove({}) //刪除全部 (籃子還存在)
db.student1.remove({'score.math': 80}); //會刪除全部匹配得到的
db.student1.remove({'score.math': 80},{justOne: true}); //刪除匹配的第一個
nodeJs 使用 mongodb
// 安裝 mongodb
npm install mongodb
nodejs 操作 mongodb
// mongo db 驅動
va r MongoClient = require('mongodb').MongoClient;
//資料庫的地址 /student 表示資料庫
// 假如資料庫不存在,沒有關係,程式會自動建立資料庫
var url = 'mongodb://localhsot:27017/student';
// 建立連線
MongoClient.connect(url,function( err,db ){
// db 引數就是連線上資料庫 實體 所有資料庫操作都建立在 實體上。
if( err ){
console.log('資料庫連線失敗');
return ;
}
console.log('資料庫成功連線');
db.collection('student').insertOne({
'name': 'mlln',
'age': 23
},function( err,result ){
if (err) {
console.log('插入失敗');
return ;
}
console.log(result);
res.send('1');
db.close();
});
});
// cmd 中檢視資料 比較多 可以使用 it 檢視下一頁
插入資料
db.collection('class1').isnertOne({'name': 'xiaoming', 'age': 21},function( err,result ){
if( err )
console.log('資料插入失敗');
console.log('資料插入成功');
});
查詢資料
var cousor = db.collection('class1').find({});
// find({}) //可以輸出查詢條件。find({'score.math': 70});
// 遍歷遊標
cousor.each(function( err,doc ){
if( doc != null ){
console.log(doc); // 輸出每條記錄
}
});
var cursor = db.collection('class1').find({'score.math': {$gt: 30}});
var cursor = db.collection('class1').find({ 'score.math': {$gt: 20} , 'score.cha': {$lt : 70}});
var cursor = db.collection('class1').find({ $or: [ {'score.math': {$gt: 50}}, {'scror.cha': {$lt: 70}} ] });
// 排序 // 1 正序 , -1 反序
var cursor = db.collection('class1').find({}).sort({'score.math': 1});
更新
覆蓋匹配的記錄 //updateOne();
db.collection('class1').updateOne({'name': 'mm'}, {'age': 23},function( err,result ){
if( err )
console.log('修改失敗');
console.log('修改成功');
});
修改欄位中的值
db.collection.('class1').updateOne({'name': 'mlln'}, { $set: {'age': 24} }, function( err,result ){
if ( err )
console.log('修改失敗');
console.log('修改成功');
});
替換記錄 //replaceOne();
db.collection('class1').replaceOne({'name': 'mlln'}, {'name': 'm1', 'age': 20});
刪除資料
db.collection('class1').deleteMany({'age',25},function( err,reslut ){
if( err )
console.log('刪除失敗');
console.log('資料刪除成功');
});
DAO層封裝
mongooose 物件與資料對應,產生ODM思想 , 一個物件new出來之後,資料庫中就存在。
// db模組封裝了所有對資料庫的常用操作
var MongoClient = require('mongodb').MongoClient;
var setting = require('../settings');
// 連線資料庫
function _connectDB(callback) {
var url = setting.dburl; // 配置檔案中讀取
MongoClient.connect(url, function (err, db) {
callback(err, db);
});
}
// 插入資料
// 往那個集合中增加,增加什麼,增加之後的事情。
exports.insertOne = function (collectionName, json, callback) {
_connectDB(function (err, db) {
if (err) {
callback(err, null);
db.close(); // 關閉資料庫
return;
}
db.collection(collectionName).insertOne(json, function (err, result) {
callback(err, result);
db.close(); // 關閉資料庫
});
});
};
// 查詢資料
// 在那個集合查詢,查什麼,分頁設定,查完之後做什麼
exports.find = function (collectionName, json, args, callback) {
if (arguments.length == 3) {
callback = args;
args = { 'pageamount': 0, 'page': 0 }
} else if (arguments.length == 4) {
} else {
throw new Error('find引數是3個或者四個');
}
var result = [];
// 應該省略的條數
var skipNum = args.pageamount * args.page;
// 數目限制
var limitNum = args.pageamount;
_connectDB(function (err, db) {
var cursor = db.collection(collectionName).find(json).skip(skipNum).limit(limitNum);
cursor.each(function (err, doc) {
// each 遍歷的時候存在問題,callback 匹配到一條,就執行一次,
// callback 意義上是隻執行一次,使用陣列解決
if (err) {
callback(err, null);
db.close(); // 關閉資料庫
return;
}
if (doc != null) {
result.push(doc); //放入結果陣列
} else {
// 遍歷結束,沒有更多文件
callback(null, result);
db.close(); // 關閉資料庫
}
});
});
};
// 刪除
exports.deleteMany = function (collectionName, json, callback) {
_connectDB(function (err, db) {
db.collection(collectionName).deleteMany(json, function (err, result) {
callback(err, result);
db.close(); // 關閉資料庫
});
});
};
// 修改
exports.updateMany = function (collectionName, json1, json2, callback) {
_connectDB(function (err, db) {
if (err) {
callback(err, null);
return false;
}
db.collection(collectionName).updateMany(json1, json2, function (err, result) {
callback(err, result);
db.close();
});
});
};
mongoDB分頁
// limit() 表示讀取的條數
// skip() 表示略過的條數
limit和skip配合使用就是分頁查詢。
假如,第一個是page=0,每頁10條,所以當前頁的查詢語句
db.student.find().limit(10).skip(page*10);
資料總數
在shell中,找尋資料總數
db.student.stats().count; // 獲得collections總數 // 需要向上取整。
db.student.find().count();
// find() ,有分頁邏輯
exports.find = function( collectionName,json,args,callback ){
if ( arguments.length == 3 ) {
callback = args;
args = {'pageamount': 0, 'page': 0}
} else if ( arguments.length == 4 ) {
} else {
throw new Error('find引數是3個或者四個');
return false;
}
// 應該省略的條數
var skipNum = args.pageamount * args.page;
//數目限制
var limitNum = args.pageamount;
_connectDB(function ( err,db ) {
var cursor = db.collection(collectionName).find(json).skip(skipNum).limit(limitNum);
cursor.each(function ( err,doc ) {
// each 遍歷的時候存在問題,callback 匹配到一條,就執行一次,
// callback 意義上是隻執行一次,使用陣列解決
if ( err ) {
callback(err,null);
return ;
}
if ( doc != null ) {
result.push( doc ); //放入結果陣列
} else {
//遍歷結束,沒有更多文件
callback(null,result);
}
});
});
};
cookie & session
cookie
需要cookie-parser中介軟體支援
- HTTP是無狀態協議。簡單地說,當你瀏覽了一個頁面,然後轉到同一個網站的另一個頁面,伺服器無法認識到,這是同一個瀏覽器在訪問同一個網站。每一次的訪問,都是沒有任何關係的。
- Cookie是一個簡單到爆的想法:當訪問一個頁面的時候,伺服器在下行HTTP報文中,命令瀏覽器儲存一個字串;瀏覽器再訪問同一個域的時候,將把這個字串攜帶到上行HTTP請求中。
- 第一次訪問一個伺服器,不可能攜帶cookie。 必須是伺服器得到這次請求,在下行響應報頭中,攜帶cookie資訊,此後每一次瀏覽器往這個伺服器發出的請求,都會攜帶這個cookie。
特點
- cookie是不加密的,使用者可以自由看到;
- 使用者可以刪除cookie,或者禁用它
- cookie可以被篡改
- cookie可以用於攻擊
- cookie儲存量很小。未來實際上要被localStorage替代,但是後者IE9相容。
作用:
記錄使用者的資訊,購買習慣,猜你喜歡。
express中的cookie, res負責設定cookie, req負責識別cookie。
cookie是沒有跨域限制
cookie使用
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.get('/',function ( req,res ) {
// maxAge 在express 是以毫秒為單位
res.cookie('xihao','tfboys',{
'maxAge': 9000,
httpOnly: true
});
res.send(req.cookies);
});
app.listen(80);
猜你喜歡
頁面中獲取原先的值,push到陣列中,然後再次設定回來。供首頁訪問。
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.get('/',function ( req,res ) {
// maxAge 在express 是以毫秒為單位
res.send('猜你喜歡' + req.cookies.mudidi );
});
app.get('/gonglve',function ( req,res ) {
var mudidi = req.query.mudidi;
//記錄使用者的喜好
//讀取使用者的喜好,然後把新的資料push設定新的資料
var mudidiArr = req.cookies.mudidi || [];
mudidiArr.push( mudidi );
res.cookie('mudidi',mudidiArr,{
'maxAge': 9000,
httpOnly: true
});
res.send(mudidi + '旅遊攻略');
});
app.listen(80);
session
需要express-session中介軟體支援
會話,session並不是天生的就有的技術,而是依賴cookie。
用於登陸。當一個瀏覽器禁用cookie的時候,登陸效果消失,或者使用者清除了cookie,登陸也消失。
session比cookie不一樣的地方,session下發的是亂碼,並且伺服器自己快取一些東西。下次瀏覽器的請求,帶著亂碼上來。此時與快取(快取是存在伺服器記憶體中,一旦伺服器關了,快取就消失)進行比較,看看匹配的是哪一個。
所以,一個亂碼,可以對應無限大的資料。(理論上),但是受記憶體限制。
任何語言中,session的使用,是“機理透明”的,它幫你設定cookie的.
var express = require('express');
var app = express();
var session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.get('/',function( req,res ){
if ( req.session.login == '1' ) {
res.send( '歡迎'+ req.session.username +'的登陸' );
} else {
res.send('沒有成功登陸');
}
});
app.get('/login',function ( req,res ) {
req.session.login = '1';
req.session.username = 'mlln';
res.send('你已經成功登陸');
});
app.listen(80)
加密
md5 加密 是函式型加密。每次加密的結果相同,沒有隨機位 //永遠不要用明文寫密碼。
特點:
- 不管加密的文字,多長多短,永遠都是32位英語字母、數字混合。
- 那怕只改一個字,密文都會大變。
- MD5沒有反函式的可能。 網上的破解工具,都是字典模式,通過列出明-密對應的字典找到明碼。
- MD5常用於版本校驗。可以比對兩個檔案、軟體是否完全一致。
node中,自帶了一個模組 crypto模組,負責加密。
//建立hash
var md5 = crypto.createHash('md5'); //建立一個hash對應
//然後update 和 digest
var password = md5.update(fields.password).digest('base64');
console.log( md52( md52('123123').slice(11,7) + md52('123123') ) );
function md52( mingma ) {
var md5 = crypto.createHash('md5');
var password = md5.update(mingma).digest('base64');
return password;
}
GM影像
gm軟體
只要伺服器需要處理圖片,那麼這個伺服器就需要安裝graphicsmagick軟體 , 還有其它的影像處理軟體。ImageMagick 。
GM軟體API
GM-API
nodejs 使用graphicsmagick。需要第三方npm的gm包
GM包執行環境 連結描述
nodejs縮圖製作
var fs = require('fs');
var gm = require('gm');
gm('./axin.jpg')
.resize(50, 50,"!")
.write('./axin.jpg', function (err) {
if (err) {
console.log(err);
}
});
nodejs頭像裁切
gm("./axin.jpg").crop(141,96,152,181).write("./2.jpg",function(err){
//141 96 是寬高 。 152 181是座標
});
索引
index
資料庫中,根據一個欄位的值,來尋找一個文件,是很常見的操作。
檢視檢索的過程
db.student.find({'name': 'username33'}).explain();
// 過程顯示
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 2,
"nscannedObjects" : 19999,
"nscanned" : 19999,
"nscannedObjectsAllPlans" : 19999,
"nscannedAllPlans" : 19999,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 16,
"indexBounds" : {
},
"server" : "YOS-01409231922:27017"
}
為了快速進行檢索,可以把唯一欄位,建立成"索引".
每個collection是已經有一個索引(預設索引_id
),再建立另外索引會具備兩條索引。
建立索引:
db.student.createIndex({ 'name': 1 }); // 1 表示的是正向。
索引的優缺點:
好處:通過索引查詢的速度會更快,因為可以從索引表中找到,當前個文件。
壞處:當資料庫中的資料不存在的時候,已經建立的索引會存在。以後插入的資料會變慢。 損失的插入的時間。得到的是查詢的時間。
複合索引
db.student.createIndex({ 'name': 1, 'address': -1 }); // 1 表示的是正向。 -1 表示負向
先以第一個條件排序,然後相同的時候以第二個條件再進行排序。(插入資料之前是一條預設的索引,索引建立之後是3條索引)
db.student.createIndex({ 'name': 1 }, {unique: true}); // unique 所有的collection都不能相同,如果相同會報錯。
適用範圍:網站並沒有大量插入的操作。(例如:同一時段並沒有大量的人在註冊)
DAO層中新增init函式使用索引:
function init() {
// 對資料庫進行一個初始化
_connectDB(function (err, db) {
if (err) {
console.log(err);
return;
}
// 建立索引
db.collection('users').createIndex(
{ 'username': 1 },
null,
function (err, results) {
if (err) {
console.log(err);
return;
}
console.log('索引建立成功');
}
);
});
}