初學Node.js
接觸到MongoDB
數據庫,閱讀資料中推薦的都是Mongoose
模塊,能夠更加方便的對數據庫進行操做,便開始接觸Mongoose
。在學習時碰到許多基礎問題,查閱了許多資料理來理解,此篇文章就是以本身的理解,記錄下入門的基礎知識,以及概括下經常使用的函數以及格式,方便從此查閱。
初學筆記不免有許多不足與錯誤歡迎指出。html
若是須要在本地測試,須要先安裝MongoDB數據庫。
在官網下載最新安裝包。安裝成功後,在命令行下進入MongoDB\bin
目錄node
mongod --dbpath D:\MongoDB\data
啓動數據庫。正則表達式
http://localhost:27017/
在瀏覽器中訪問這地址,訪問正常則數據庫啓動成功。
更詳細的說明能夠查看《MongoDB的下載、安裝與部署》mongodb
npm install mongoose
在已經安裝過Node.js的電腦上,進入工做目錄輸入以上命令便可安裝Mongoose模塊。數據庫
Robomongo
是一款不錯的可視化工具,Windows、MacOS、Linux平臺都有,界面也簡潔。雖然有收費,普通操做免費版足夠用。
官網下載npm
在須要使用的js文件中引入模塊。api
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/mongodb');
URL以mongodb://
+ [用戶名:密碼@]
+數據庫地址[:端口]
+ 數據庫名
。(默認端口27017)
須要對鏈接情況進行判斷,能夠用如下代碼:數組
db.connection.on("error", function (error) { console.log("數據庫鏈接失敗:" + error); }); db.connection.on("open", function () { console.log("數據庫鏈接成功"); }) db.connection.on('disconnected', function () { console.log('數據庫鏈接斷開'); })
最常接觸到的有三個概念Schema
、Model
、Entity
。按本身理解,Schema
是定義數據庫的結構。相似建立表時的數據定義,但比建立數據庫能夠作更多的定義,只是沒辦法經過Schema對數據庫進行更改。Model
是將Schema定義的結構賦予表名。但可用此名對數據庫進行增刪查改。Entity
是將Model與具體的數據綁定,能夠對具體數據自身進行操做,例如保存數據。瀏覽器
Schema用來定義數據庫文檔結構,數據庫有什麼字段、字段是什麼類型、默認值、主鍵之類的信息。除了定義結構外,還能定義文檔的實例方法,靜態模型方法,複合索引,中間件等。詳情查看mongoose官方文檔。
在引入Mongoose模塊var mongoose = require('mongoose')
的js文件中進行操做。安全
var blogSchema = new mongoose.Schema({ title: String, comments: [{ body: String, date: Date }], date: { type: Date, default: Date.now }, hidden: Boolean, meta: { votes: Number, favs: Number } })
這樣即定義了一個名爲blogSchema
的Schema。
如需再添加數據,用add
方法。
blogSchema.add( { author: String, body: String} );
資料中介紹,Shema
不只定義了文檔的結構和屬性,還能夠定義文檔的插件、實例方法、靜態方法、複合索引文檔生命週期鉤子,具體還需查看官方文檔。
Schema.Type
是Mongoose內部定義的數據類型。基本類型有:String
、Number
、Date
、Boolean
、Array
、Buffer
、Mixed
、ObjectId
。
Mixed
混合數據類型,能夠直接定義{}
來使用,如下兩種形式等價。
new Schema({mixed: {Schema.Types.Mixed} }); new Schema({mixed: {} });
ObjectId
儲存在數據庫中的每一個數據都會有默認的主鍵_id
,默認存儲的是ObjectId
。ObjectId
是一個12字節的BSON
類型字符串。按照字節順序依次表明:
4字節:UNIX時間戳
3字節:表示運行MongoDB的機器
2字節:表示生成此_id的進程
3字節:由一個隨機數開始的計數器生成的值
var blogModel = mongoose.model('Blog', blogSchema);
將名爲blogSchema
的Schema與Blog
名字綁定,便是存入數據庫的名字,但存入數據庫中的名字是Blogs
,會自動添加一個s
。
這裏將Model命名爲blogModel
,須要對Blog
表操做的話,都須要使用變量名blogModel
。
能夠綁定具體數據對Model實例化。
var blogEntity = new blogModel({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } })
這裏將名爲blogModel
的Model實例化。以後咱們能夠用blogEntity
名對數據進行保存並執行回調。
blogEntity.save(function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); })
在日常使用SQL語句操做數據庫時,取得數據後先組織成SQL語句,而後放入執行語句中執行。這裏理解也是相似,取得數據先進行實例化,這一步相似於組織成SQL語句,而後再作具體操做例如上面的Save
操做。但因爲Node.js是異步操做,因此返回的數據利用回調函數來進行操做。
知道了以上概念後就能夠對數據進行操做了,下面將列出一些經常使用的資料,並附上相應的例子。
全部的參數都是以JSON對象
形式傳入。
var doc = ({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } }; blogModel.create(doc, function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
Model#save([options], [options.safe], [options.validateBeforeSave], [fn])
var blogEntity = new blogModel({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } }); blogEntity.save(function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
多條數據插入,將多條數據一次性插入,相對於循環使用create
保存會更加快。
blogModel.insertMany([ {title: "mongoose1", author: "L"}, {title: "mongoose2", author: "L"} ], function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
conditions
:查詢條件;projection
:控制返回的字段;options
:控制選項;callback
:回調函數。
blogModel.find({title: "Mongoose", meta.votes: 100}, {title: 1, author: 1, body: 1}, function(err, docs){ if(err) console.log(err); console.log('查詢結果:' + docs); })
查詢「title」標題爲「Mongoose」,而且「meta」中「votes」字段值爲「100」的記錄,返回僅返回「title」、「author」、「body」三個字段的數據。
Model.findOne([conditions], [projection], [options], [callback])
conditions
:查詢條件;projection
:控制返回的字段;options
:控制選項;callback
:回調函數。
只返回第一個查詢記錄。
id
:指定_id
的值;projection
:控制返回的字段;options
:控制選項;callback
:回調函數。
conditions
:查詢條件;doc
:須要修改的數據,不能修改主鍵(_id
);options
:控制選項;callback
:回調函數,返回的是受影響的行數。options
有如下選項:
safe (boolean): 默認爲true。安全模式。
upsert (boolean): 默認爲false。若是不存在則建立新記錄。
multi (boolean): 默認爲false。是否更新多個查詢記錄。
runValidators: 若是值爲true,執行Validation驗證。
setDefaultsOnInsert: 若是upsert選項爲true,在新建時插入文檔定義的默認值。
strict (boolean): 以strict模式進行更新。
overwrite (boolean): 默認爲false。禁用update-only模式,容許覆蓋記錄。
blogModel.update({title: "Mongoose"}, {author: "L"}, {multi: true}, function(err, docs){ if(err) console.log(err); console.log('更改爲功:' + docs); })
以上代碼先查詢「title」爲「Mongoose」的數據,而後將它的「author」修改成「L」,「multi」爲true容許更新多條查詢記錄。
一次更新多條
一次更新一條
Model.findByIdAndUpdate(id, [update], [options], [callback])
id
:指定_id
的值;update
:須要修改的數據;options
控制選項;callback
回調函數。options
有如下選項:
new: bool - 默認爲false。返回修改後的數據。
upsert: bool - 默認爲false。若是不存在則建立記錄。
runValidators: 若是值爲true,執行Validation驗證。
setDefaultsOnInsert: 若是upsert選項爲true,在新建時插入文檔定義的默認值。
sort: 若是有多個查詢條件,按順序進行查詢更新。
select: 設置數據的返回。
Model.findOneAndUpdate([conditions], [update], [options], [callback])
conditions
:查詢條件;update
:須要修改的數據;options
控制選項;callback
回調函數。options
有如下選項:
new: bool - 默認爲false。返回修改後的數據。
upsert: bool - 默認爲false。若是不存在則建立記錄。
fields: {Object|String} - 選擇字段。相似.select(fields).findOneAndUpdate()。
maxTimeMS: 查詢用時上限。
sort: 若是有多個查詢條件,按順序進行查詢更新。
runValidators: 若是值爲true,執行Validation驗證。
setDefaultsOnInsert: 若是upsert選項爲true,在新建時插入文檔定義的默認值。
passRawResult: 若是爲真,將原始結果做爲回調函數第三個參數。
blogModel.remove({author: "L"}, function(err, docs){ if(err) console.log(err); console.log('刪除成功:' + docs); })
刪除「author」值爲「L」的記錄。
id
:指定_id
的值;update
:須要修改的數據;options
控制選項;callback
回調函數。options
有如下選項:
sort: 若是有多個查詢條件,按順序進行查詢更新。
select: 設置數據的返回。
conditions
:查詢條件;update
:須要修改的數據;options
控制選項;callback
回調函數。options
有如下選項:
sort: 若是有多個查詢條件,按順序進行查詢更新。
maxTimeMS: 查詢用時上限。
select: 設置數據的返回。
在以前的查詢說明中僅演示了肯定值的查詢,若是遇到更加複雜的狀況就須要使用其餘一些方法。
詳細的文檔能夠在這兒查找 mongodb查詢符。
執行查詢,回調函數。
使用find()
、$where
之類查詢返回的是Mongoose本身封裝的Query對象,使用find()
能夠在函數最後接上回調來獲取查詢到的數據。
使用鏈式語句時,能夠在以後接.exec()
執行查詢,並指定回調函數。
blogModel.find({title: "Mongoose", meta.votes: 100}, {title: 1, author: 1, body: 1}).exec(function(err, docs){ if(err) console.log(err); console.log('查詢結果:' + docs); })
配合各類查詢符能夠方便的實現複雜的查詢。
好比我須要查詢「title」中以「Mongoose」開頭,而且「meta」中「votes」的值小余100。而且按「meta」中「votes」的值升序排序。
blogModel.and([ { title: { $regex: "Mongoose.+","$options":"i"}}, { meta.votes: { $lt: 100}} ).sort({ meta.votes: 1} ).exec(function(err, docs){ if(err) console.log(err); console.log('查詢結果:' + docs); });
$equals 等於 / $gt 大於 / $gte 大於等於 / $lt 小余 / $lte 小余等於 / $ne 不等於 / $in 在數組中 / $nin 不在數組中
blogModel.find({meta.votes: {$lt: 100}});
查詢「meta」中的「votes」字段值小余100的數據。
blogModel.find({title: {$in: ['Mongoose', 'Mongodb', 'Nodejs']}});
查詢「title」爲「Mongoose」或「Mongodb」或「Nodejs」其中之一的數據。
blogModel.find({ $and: [ {meta.votes: {$gte: 50}}, {meta.votes: {$lt: 100}} ]});
查詢「meta」中的「votes」字段值大於等於50到小余100的數據。
blogModel.find({ $nor: [ {meta.votes: 50}, {meta.votes: 100} ]});
查詢「meta」中的「votes」字段值不等於50和不等於100的數據。
以上例子也能夠寫成這樣形式,比較清晰,其餘類同
blogModel.and([ {meta.votes: {$gte: 50}}, {meta.votes: {$lt: 100}} ]); blogModel.nor([ {meta.votes: 50}, {meta.votes: 100} ]);
$exists 查詢的字段值是否存在
blogModel.find({ title: {$exists: true}}); blogModel.where('title').exists(true);
查詢存在「title」字段的數據。
$mod 與數據進行取模運算篩選
blogModel.find({ meta.votes: {$mod: [4, 0]}}); blogModel.where('meta.votes').$mod(4, 0);
查找「meta」中的「votes」字段值與4取模後,值爲0的數據。
$regex 使用正則表達式查詢數據
blogModel.find({ title: { $regex: "Mongoose.+","$options":"i"}});
搜索以「Mongoose」開頭的「title」字段,「options」中的「i」表明不區分大小寫。$options
參數與其他用法能夠查看mongodb文檔中 $regex 一節。
$where 支持js表達式查詢
blogModel.find({ $where: 'this.comments.length === 10 || this.name.length === 5' }); blogModel.$where(function() { return this.comments.length === 10 || this.name.length === 5; });
Query#all([path], val) 查詢數組的自己及超集
blogModel.find( tags: ['nodejs', 'mongoose']);
查詢「tags」的字段值同時包含有['nodejs', 'mongoose']的數據。只要值中包含此數組即返回數據,如果只包含數組中的一個則不返回此數據。
Query#elemMatch(path, criteria) 查詢數組的交集
blogModel.find( $elemMatch: { tags: 'mongoose', author: 'L'});
查詢「tags」爲「mongoose」或是「author」爲「L」的數據。
Query#size([path], val) 查詢指定大小的數組
blogModel.find( tags: { $size: 2}); blogModel.where('tags').size(2);
查詢「tags」數組中包含兩個元素的數據。
Query#limit(val) 限制查詢返回的數量
blogModel.find( tags: 'mongoose').limit(5);
查詢「tags」爲「mongoose」的數據,只返回前5個查詢結果。
Query#skip(val) 跳過前N個查詢結果
blogModel.find( tags: 'mongoose').skip(10).limit(5);
查詢「tags」爲「mongoose」的數據,跳過前10個查詢結果,返回從第11個開始的五個查詢結果。
作分頁時經常使用到這兩個,但數據量過大時就會有性能問題。
Query#sort(arg) 對結果按某個指定字段進行排序
1
、asc
爲升序,-1
、desc
爲降序。能夠對一個字段進行排序,也能夠是多個。
blogModel.find( tags: 'mongoose').skip(10).limit(5).sort("{ meta.votes: 1}");
查詢「tags」爲「mongoose」的數據,跳過前10個查詢結果,返回從第11個開始的五個查詢結果。以後按「votes」進行升序排序。
blogModel.count({ title: 'mongoose'}, function(err, docs){});
統計「title」爲「mongoose」數據的數量
Query#select(arg) 選擇指定字段
在查詢中能夠選擇指定的查詢字段,或者排除指定的字段。+
爲包含,-
爲排除。
blogModel.select('title body');
只包含「title」、「body」字段。
blogModel.select('-title -body');
排除「title」、「body」字段。