Mongoose增查改刪學習筆記

初學Node.js接觸到MongoDB數據庫,閱讀資料中推薦的都是Mongoose模塊,可以更加方便的對數據庫進行操作,便開始接觸Mongoose。在學習時碰到許多基礎問題,查閱了許多資料理來理解,此篇文章就是以自己的理解,記錄下入門的基礎知識,以及歸納下常用的函數以及格式,方便今后查閱。
初學筆記難免有許多不足與錯誤歡迎指出。

環境搭建

安裝MongoDB

如果需要在本地測試,需要先安裝MongoDB數據庫。
官網下載最新安裝包。安裝成功后,在命令行下進入MongoDB\bin目錄

mongod --dbpath D:\MongoDB\data

啟動數據庫。

http://localhost:27017/

在瀏覽器中訪問這地址,訪問正常則數據庫啟動成功。
更詳細的說明可以查看《MongoDB的下載、安裝與部署》

Node.js中安裝模塊

npm install mongoose

在已經安裝過Node.js的電腦上,進入工作目錄輸入以上命令即可安裝Mongoose模塊。

可視化工具

Robomongo

Robomongo是一款不錯的可視化工具,Windows、MacOS、Linux平臺都有,界面也簡潔。雖然有收費,普通操作免費版足夠用。
官網下載

引入與連接

引入模塊

在需要使用的js文件中引入模塊。

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('數據庫連接斷開');  
})

基本概念

最常接觸到的有三個概念SchemaModel、Entity。按自己理解,
Schema是定義數據庫的結構。類似創建表時的數據定義,但比創建數據庫可以做更多的定義,只是沒辦法通過Schema對數據庫進行更改。
Model是將Schema定義的結構賦予表名。但可用此名對數據庫進行增刪查改。
Entity是將Model與具體的數據綁定,可以對具體數據自身進行操作,例如保存數據。

Schema

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

Schema.Type是Mongoose內部定義的數據類型。基本類型有:String、Number、Date、Boolean、Array、BufferMixedObjectId。

Mixed
混合數據類型,可以直接定義{}來使用,以下兩種形式等價。

new Schema({mixed: {Schema.Types.Mixed} });
new Schema({mixed: {} });

ObjectId
儲存在數據庫中的每個數據都會有默認的主鍵_id,默認存儲的是ObjectId
ObjectId是一個12字節的BSON類型字符串。按照字節順序依次代表:
4字節:UNIX時間戳
3字節:表示運行MongoDB的機器
2字節:表示生成此_id的進程
3字節:由一個隨機數開始的計數器生成的值

Model

var blogModel = mongoose.model('Blog', blogSchema);

將名為blogSchema的Schema與Blog名字綁定,即是存入數據庫的名字,但存入數據庫中的名字是Blogs,會自動添加一個s。
這里將Model命名為blogModel,需要對Blog表操作的話,都需要使用變量名blogModel。

Entity

可以綁定具體數據對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是異步操作,所以返回的數據利用回調函數來進行操作。

知道了以上概念后就可以對數據進行操作了,下面將列出一些常用的資料,并附上相應的例子。

增查改刪(CRUD)

所有的參數都是以JSON對象形式傳入。

增(C)

Model.create(doc(s), [callback])

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);
});

Model.insertMany(doc(s), [options], [callback])

多條數據插入,將多條數據一次性插入,相對于循環使用create保存會更加快。

blogModel.insertMany([
    {title: "mongoose1", author: "L"}, 
    {title: "mongoose2", author: "L"}
    ], function(err, docs){
        if(err) console.log(err);
        console.log('保存成功:' + docs);
});

查(R)

Model.find(conditions, [projection], [options], [callback])

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:回調函數。
只返回第一個查詢記錄。

Model.findById(id, [projection], [options], [callback])

id:指定_id的值;projection:控制返回的字段;options:控制選項;callback:回調函數。

改(U)

Model.update(conditions, doc, [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.updateMany(conditions, doc, [options], [callback])

一次更新多條

Model.updateOne(conditions, doc, [options], [callback])

一次更新一條

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: 如果為真,將原始結果作為回調函數第三個參數。

刪(D)

Model.remove(conditions, [callback])

blogModel.remove({author: "L"}, function(err, docs){
    if(err) console.log(err);
    console.log('刪除成功:' + docs);
})

刪除“author”值為“L”的記錄。

Model.findByIdAndRemove(id, [options], [callback])

id:指定_id的值;update:需要修改的數據;options控制選項;callback回調函數。
options有以下選項:
  sort: 如果有多個查詢條件,按順序進行查詢更新。
  select: 設置數據的返回。

Model.findOneAndRemove(conditions, [options], [callback])

conditions:查詢條件;update:需要修改的數據;options控制選項;callback回調函數。
options有以下選項:
  sort: 如果有多個查詢條件,按順序進行查詢更新。
  maxTimeMS: 查詢用時上限。
  select: 設置數據的返回。

復雜條件查詢

在之前的查詢說明中僅演示了確定值的查詢,如果遇到更加復雜的情況就需要使用其他一些方法。
詳細的文檔可以在這兒查找 mongodb查詢符。

Query#exec([operation], [callback])

執行查詢,回調函數。
使用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”其中之一的數據。

邏輯查詢運算符

$or 或 / $and 與 / $nor

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)  對結果按某個指定字段進行排序

1asc為升序,-1、desc為降序。可以對一個字段進行排序,也可以是多個。

blogModel.find( tags: 'mongoose').skip(10).limit(5).sort("{ meta.votes: 1}");

查詢“tags”為“mongoose”的數據,跳過前10個查詢結果,返回從第11個開始的五個查詢結果。之后按“votes”進行升序排序。

Query#count([criteria], [callback])  計數

blogModel.count({ title: 'mongoose'}, function(err, docs){});

統計“title”為“mongoose”數據的數量

Query#select(arg)  選擇指定字段

在查詢中可以選擇指定的查詢字段,或者排除指定的字段。+為包含,-為排除。

blogModel.select('title body');

只包含“title”、“body”字段。

blogModel.select('-title -body');

排除“title”、“body”字段。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 參考深入淺出mongoose 連接mongoose mongoose連接數據庫有兩種方式第一種: 第二種: mon...
    bacbcc94613b閱讀 12,344評論 1 27
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測試 ...
    KeKeMars閱讀 6,356評論 0 6
  • Mongodb 配置選項 通常在mongod.conf中 配置文件 設置了配置文件后啟動時以自定義的配置文件啟動:...
    AkaTBS閱讀 1,088評論 0 6
  • 參考資料https://www.npmjs.com/package/mongodbhttps://docs.mon...
    程序員有話說閱讀 758評論 0 4
  • 感恩周末睡個懶覺,舒服。謝謝你,謝謝你,謝謝你。 感恩美美的吃了頓豐盛的早餐 ,謝謝你,謝謝你,謝謝你。 感恩鄰居...
    王貽賢閱讀 225評論 0 0