日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mongoose操作mongodb

發布時間:2023/12/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mongoose操作mongodb 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://mongoosejs.com/docs/api.html#index-js
mongoose是nodejs環境下操作mongodb的模塊封裝,使用mongoose之后,實際上只需要在mongodb中創建好數據庫與用戶,集合的定義、創建、操作等直接使用mongoose即可。

  • 一、連接
  • 二、重要概念
  • 三、基本操作
    • 1、Schema
    • 2、Model
    • 3、實例化document
    • 4、保存數據
    • 5、文檔查詢
    • 6、文檔更新
    • 7、文檔刪除
    • 8、自定義方法
    • 9、虛擬屬性
    • 10、前置與后置鉤子

一、連接

let mongoose = require('mongoose');//連接mongodb //非auth模式 //mongoose.connect('mongodb://localhost:27017/mall'); //auth模式 /** mongodb 為協議 第一個mall: 連接數據庫的用戶名 123456: 用戶的密碼 localhost: mongodb地址 27017: mongodb端口號 第二個mall: 數據庫名字 **/ mongoose.connect('mongodb://mall:123456@localhost:27017/mall');//連接失敗 mongoose.connection.on('connected',() => {console.log('mongodb connected!'); });//連接成功 mongoose.connection.on('error',(err) => {console.log('mongodb connect fail:'+err); });//連接斷開 mongoose.connection.on('disconnected',() => {console.log('mongodb connect disconnected!'); });// connection的事件列表可查看:http://mongoosejs.com/docs/api.html#connection_Connection // 或 ./node_modules/mongoose/lib/connection.js#Connection()// 關閉的兩種方式 // mongoose.connection.close(); 等同于 db.close(); // mongoose.disconnect();

二、重要概念


  Mongooose中,有三個比較重要的概念,Schema、Model、Document。Schema生成Model,Model實例化成為Document。

  Schema用于定義數據庫的結構。類似創建表時的數據定義(不僅僅可以定義文檔的結構和屬性,還可以定義文檔的實例方法、靜態模型方法、復合索引等),每個Schema會映射到mongodb中的一個collection,Schema不具備操作數據庫的能力。

  Model是由Schema編譯而成的構造器,具有抽象屬性和行為,可以對數據庫進行增刪查改。Model的每一個實例(instance)就是一個文檔document。

  Document是new Model后創建的實例,它的操作會影響數據庫。

三、基本操作

1、Schema

Schema是對mongodb中某個集合的結構描述,它定義一個集合中應該包含哪些數據項,每個數據項的數據類型與檢查約束。可以想象成一個抽象類,只有定義,沒有實現。就是規定好某個集合的框架應該是怎么樣的。也可以理解是mysql中的表結構。
可以為數據項指定的數據類型有8種:

String 字符串 Number 數字 Date 日期 Buffer 二進制 Boolean 布爾值 Mixed 混合類型 ObjectId 對象ID Array 數組

創建Schema

const mongoose = require('mongoose') //獲取Schema const Schema = mongoose.Schema;//聲明一個Schema實例,實際就是創建一個集合的結構框架 let animalSchema = new Schema({title: String, //類型可以是首字母大寫age: 'number', //類型也可以寫成字符串全小寫food: [{ //數組name: String}] });//如果需要為animalSchema增加屬性,可以使用add animalSchema.add({sex: {type: String,enum: ['male', 'female'] //規定,字段值為枚舉約束,只能填male/female} });

創建Schema時可以有一系列的約束條件,類似mysql中字段的非空、唯一等約束。
基本語法是:

{name: {type:String, validator:value}}

常用的約束有:

required: 數據必須填寫 default: 默認值 min: 最小值(只適用于數字) max: 最大值(只適用于數字) match: 正則匹配(只適用于字符串) enum: 枚舉匹配(只適用于字符串) validate: 自定義匹配

其中validate是自定義約束
例如要自定義檢查長度

// 自定義長度檢查 let lengthValidate = (param) => {return param.length <= 10 };//如果需要為animalSchema增加屬性,可以使用add animalSchema.add({sex: {type: String,enum: ['male', 'female'], //規定,字段值為枚舉約束,只能填male/femalevalidate: lengthValidate} });

2、Model

model是根據Schema定義的結構框架生成一個映射mongodb的數據模型,可以把它理解是一個類,是根據Schema創建的一個類,他的數據結構是依據Schema生成的,這個類用來生成document實例。

//通過schema構建model,第一個參數是給model起個名字,第二個參數是構造這個model所依據的schema let animalModel = mongoose.model('animalModel', animalSchema);

3、實例化document

document是相當于是mongodb中的每一條數據了,它是通過new一個model得到的。

// 通過實例化model得到document,document的數據項需根據schema定義的結構來寫// 通過實例化model得到document,document的數據項需根據schema定義的結構來寫let cat = new animalModel({title: '貓咪',food: [{name: '魚'},{name: '火腿'}],sex: 'male'});

到這一步,mongodb中還沒有animalMode集合以及數據。

4、保存數據

  • 1、save()
    在mongoose中保存數據,實際就是保存某個document,document通過model實例化來創建。document的save()方法可以將document映射保存到mongodb中,save()方法中可以傳遞一個回調函數作為參數。因為是在document上調用,自然一次只保存一條文檔。
    方法原型:
save(function (err, document) {}) //回調函數中第二個參數是使用保存的數據形成的對象

保存cat:

//保存document,映射成為一條記錄 cat.save((err, catObj) => {if (err) {console.log('保存失敗');console.info(err);} else {console.info(catObj);} });

保存后打印:

{ title: '貓咪',food: [ { name: '魚', _id: 5a96555e95f678530054f918 },{ name: '火腿', _id: 5a96555e95f678530054f917 } ],sex: 'male',_id: 5a96555e95f678530054f919,__v: 0 }

保存后這個回調中的第二個參數就被填充好值,其中的主鍵_id也在其中,__v是mongoose用來管理數據版本號的標識,自己不用動。
這時看mongodb中已有集合,集合中已經有一條數據(文檔)了。

注意:
1、從上圖可以看出來,集合的名字是根據mongoose.model('animalModel', animalSchema)中第一個參數來的,變成小寫且復數形式,如果結尾是數字則不變。比如這個地方如果第一個參數給的是’animal’,則生成的集合名稱就應該是’animals’。
2、在mongoose中操作mongodb,因為有了schema、model、ducument的概念,就不是像mysql一樣,事先創建好表結構,而是根據數據結構設計,在代碼中聲明好schema,再生成model、創建document,進行數據操作。

  • 2、create()
    和save()不一樣的是,create()不是在document上調用的,而是在model上調用的,并且可以一次保存多條文檔。
    接著用上面的animalModel,這次不去new它了,也就是不去操作document了,直接用mongoose.model出來的model。同時保存兩條狗。
let dog1 = {title: '1號狗狗',food: [{name: '骨頭'},{name: '肉肉'},],sex: 'male'};let dog2 = {title: '2號狗狗',food: [{name: '骨頭'},{name: '肉肉'},],sex: 'male'};animalModel.create(dog1, dog2, (err, rsObj1, rsObj2) => {if (err) {console.log('保存失敗');console.info(err);} else {console.log('保存成功');console.info(rsObj1);console.info(rsObj2);}});

打印的結果:

保存成功 { title: '1號狗狗',food: [ { name: '骨頭', _id: 5a96607b5ce650532494f010 },{ name: '肉肉', _id: 5a96607b5ce650532494f00f } ],sex: 'male',_id: 5a96607b5ce650532494f011,__v: 0 } { title: '2號狗狗',food: [ { name: '骨頭', _id: 5a96607b5ce650532494f013 },{ name: '肉肉', _id: 5a96607b5ce650532494f012 } ],sex: 'male',_id: 5a96607b5ce650532494f014,__v: 0 }

再看看mongodb中:

注意:這里也驗證了一個問題,就是如果model對應的集合已經存在于mongodb中了,則會直接往這個集合中添加文檔,如果還沒有,則會創建集合。所以在上面保存貓咪的時候,同時創建了集合與添加貓咪文檔,而這里的狗狗,直接添加文檔。

  • 3、insertMany()
    insertMany()也是model的方法,一次插入多條數據,注意回調中的返回值是所有結果對象的數組。
let monkey1 = {title: '1號猴猴',food: [{name: '香蕉'},{name: '桃'},],sex: 'male'};let monkey2 = {title: '2號猴猴',food: [{name: '香蕉'},{name: '桃'},],sex: 'male'};animalModel.insertMany([monkey1, monkey2], (err, rsArr) => {if (err) {console.log('保存失敗');console.info(err);} else {console.log('保存成功');console.info(rsArr);}});

打印結果:

保存成功 [ { title: '1號猴猴',food: [ [Object], [Object] ],sex: 'male',_id: 5a967c3f44d6d753b6cd6354,__v: 0 },{ title: '2號猴猴',food: [ [Object], [Object] ],sex: 'male',_id: 5a967c3f44d6d753b6cd6357,__v: 0 } ]

5、文檔查詢

mongodb中的數據查詢就是查文檔。

  • 1、find()
    find()是用在model上的,這一點很容易理解,既然是查詢數據,那么當前肯定是不明確要得到的文檔結果是怎樣的,方法也就不會在document上。
    find()方法在官方文檔中的描述是:
Model.find()Parameters [callback] ?Function? Returns:?Query?Finds documents The conditions are cast to their respective SchemaTypes before the command is sent.Example: // named john and at least 18 MyModel.find({ name: 'john', age: { $gte: 18 }});// executes immediately, passing results to callback MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});// name LIKE john and only selecting the "name" and "friends" fields, executing immediately MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })// passing options MyModel.find({ name: /john/i }, null, { skip: 10 })// passing options and executing immediately MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {});// executing a query explicitly var query = MyModel.find({ name: /john/i }, null, { skip: 10 }) query.exec(function (err, docs) {});// using the promise returned from executing a query var query = MyModel.find({ name: /john/i }, null, { skip: 10 }); var promise = query.exec(); promise.addBack(function (err, docs) {});

官方示例find的用法非常清晰了,find方法最簡的參數是只給一個回調函數,表示查詢所有結果,相當于是sql中的select * from 表名。
find()方法返回值是query對象,query對象有exec和一系列方法,exec()可以執行準備好的find()查詢,回調得到結果。

回到animal示例中:
查詢animalmodels集合中所有的文檔:

//方式一: animalModel.find((err, rs) => {if (err) {console.log('查詢失敗');console.info(err);} else {console.log('查詢成功');console.info(rs);}});//方式二:let animalQuery = animalModel.find();animalQuery.exec((err, rs) => {if (err) {console.log('查詢失敗');console.info(err);} else {console.log('查詢成功');console.info(rs);}});//兩種方式的結果是一樣的,返回的rs是一個包含集合中所有文檔的數組

find()的完整參數列表是:
Model.find([查詢條件], [返回字段列表], [設置選項], [回調函數]);
對于第一個參數,比如age: { $gte: 18 },表示要查詢年齡大于等于18的文檔。常用的條件操作符有:

$lt$lte$gt$gte$in$nin$eq$ne$or(model.find({$or:[{ color: 'red' }, { status: 'emergency' }]}))、$and$not$nor$exits(值是否存在,model.find({name:{$exits:true}}))、$all(通常用來匹配數組里面的鍵值,匹配多個值(同時具有) $all:[“apple”,“banana”,“peach”]})、$size(用來查詢數組的長度值 model.find({name:{$size:3}}); 匹配name的數組長度為3

有一個特殊的操作符$where,可以靈活的設置查詢條件,$where后可以直接寫任何的js作為查詢條件,但實際上完全可以使用model.where()方法來代替,where()會更加方便。

{$where:"this.x == this.y"} {$where:function(){return obj.x !== obj.y; }}

這些操作符在find的第一個參數中使用,query中也有一一對一個的方法。

對于第二個參數,可以設置要返回的字段列表,{name:1,_id:0}表示返回name字段,不返回_id字段。

對于第三個參數,官方示例中用到了一個skip,還有limit、sort。

除了find()外,還有findById()、findOne(),與find的用法都是一樣的。只不過findById的第一個參數是準確的id值。這兩個方法都只返回一條文檔。

  • 2、where()
    官網上這么介紹的
Model.where() Parameters [val] ?Object? optional valueReturns:?Query? Creates a Query, applies the passed conditions, and returns the Query.

官方示例:

User.find({age: {$gte: 21, $lte: 65}}, callback); 等同于 User.where('age').gte(21).lte(65).exec(callback);

因為where返回的是query對象,所以可以鏈式調用:

User .where('age').gte(21).lte(65) .where('name', /^b/i) ... etc

所以在實際的使用過程中,用query對象來進行查詢是比較方便的,用find()的返回值query鏈式調用其他方法,或者用where()的返回值query鏈式調用其他方法,最后用exec(callback)得到結果,這樣比較清晰。query有一系列的方法,異步官方文檔。

  • 3、query常用方法
sort 排序 skip 跳過 limit 限制 select 顯示字段 exect 執行 count 計數 distinct 去重

關于分頁與排序,query的三個方法:
query.limit(20); //只返回前20個內容
query.skip(2); //跳過多少條,實際就是開始的索引
query.sort({name:1,age:-1}); //1升序,2降序

6、文檔更新

  • 1、update()
    Model.update(conditions, doc, [options], [callback])
    第一個參數conditions為查詢條件,第二個參數doc為需要修改的數據,第三個參數options為控制選項,第四個參數是回調函數。
    options有以下選項:
safe (boolean): 默認為true。安全模式。upsert (boolean): 默認為false。如果不存在則創建新記錄。multi (boolean): 默認為false。是否更新多個查詢記錄。runValidators: 如果值為true,執行Validation驗證。setDefaultsOnInsert: 如果upsert選項為true,在新建時插入文檔定義的默認值。strict (boolean): 以strict模式進行更新。overwrite (boolean): 默認為false。禁用update-only模式,允許覆蓋記錄。

把名字叫貓咪的文檔的名字更新成貓貓:

animalModel.update({title :{$eq: '貓咪'}}, {title: '貓貓'}, (err, rs) => {if (err) {console.log('更新失敗');console.info(err);} else {console.log('更新成功');console.info(rs);}});

如果不設置multi的話,即使有多條符合條件的文檔,也只更新一條。
如果設置options里的upsert參數為true,若沒有符合查詢條件的文檔,mongo將會綜合第一第二個參數向集合插入一個新的文檔。

  • 2、updateMany()
    updateMany()與update()的區別是更新多個文檔,即使設置{multi:false}也更新多個。

  • 3、updateOne()
    updateOne()只更新找到的第一條數據,即使設置{multi:true}只更新一個。

  • 4、數組更新
    update第二個參數,實際可以寫成{$set: {title: '貓貓'}},$set操作符表示設值,如果要更新的是數組,可以有以下操作符:

$addToSet // 當且僅當待添加到數組的元素是當前數組所沒有時,才會去添加 $pop // 當指定數組的修飾符值為-1時,刪除該數組的第1個元素;當值為1時,刪除最后一個元素 $pull // 刪除指定查詢條件下的數組元素 $pullAll // 刪除數組中符合給定的集合的值的所有元素,與$pull的區別于目標刪除元素是被逐一列舉出來的 $push // 將元素添加到指定的數組中

給貓添加一個食物:

animalModel.update({title :{$eq: '喵星人'}},{$addToSet:{food: {name: '蛋黃派'}}},(err,rs) =>{if (err) {console.info("保存失敗");console.info(err);} else {console.info("保存成功");console.info(rs);}});

結果:

保存成功 { n: 1, nModified: 1, ok: 1 }
  • 5、其他
    關于其他更新方法還有findOneAndUpdate()、findByIdAndUpdate()。
    通過查詢+保存操作也可以實現更新,查詢的結果實際是一個document對象,調用save方法,猜想是通過_id與_v來進行的比對,將直接更新本條記錄。
animalModel.where('title').eq('貓貓').exec((err, rs) => {if (err) {console.info(err);} else {console.info(rs);rs.forEach(function(item,index,array){item.title = "喵星人";item.save((err,rs) =>{if (err) {console.info("保存失敗");console.info(err);} else {console.info("保存成功");console.info(rs);}});});}});

7、文檔刪除

  • 1、remove()
    remove方法存在兩個位置,一個是model上,一個是ducument上,model上就是根據條件去刪除集合內某些文檔,文檔上就是刪除自己。
model.remove(conditions, [callback]) document.remove([callback])

示例:

//model刪除animalModel.remove({title :{$eq: '喵星人'}},(err,rs) =>{if (err) {console.info("刪除失敗");console.info(err);} else {console.info("刪除成功");console.info(rs);}});//document刪除animalModel.where('title').eq('2號猴猴').exec((err, rs) => {if (err) {console.info(err);} else {console.info(rs);rs.forEach(function(item,index,array){item.remove((err,rs) =>{if (err) {console.info("刪除失敗");console.info(err);} else {console.info("刪除成功");console.info(rs);}});});}});
  • 2、findOneAndRemove()
    model的remove()會刪除符合條件的所有數據,如果只刪除符合條件的第一條數據,可以使用model的findOneAndRemove()方法
Model.findOneAndRemove(conditions, [options], [callback])
  • 3、findByIdAndRemove()
    通過id刪除文檔
Model.findByIdAndRemove(id, [options], [callback])
  • 4、其他
    所有刪除方法的回調函數都不能省略,否則不成功。要么寫在方法的回調函數參數中,如果不寫回調函數參數,則可以在最后調用.exec()。

8、自定義方法

mongoose中可以利用已有的api,自定義自己的方法來處理特定的業務需要。

  • 1、實例方法
    通過new model得到的document實例有很多增刪改查的方法,如上面的save()方法用來保存文檔,我們可以給實例增加自定義方法來實現特定的業務邏輯,增加之后就可以像調用save一樣來調用自己的方法,給document增加自定義方法是通過擴展Schema的methods屬性來完成的。

為animalSchema擴展document實例方法:

//為document實例添加eat方法,返回所有喜歡吃的食物 animalSchema.methods.eat = function () {let foodList = this.food;let foodStr = '';foodList.forEach(function (item, index, arr) {if (index == 0) {foodStr += item.name;} else {foodStr += ","+item.name;}});return foodStr; };

document實例調用:

animalModel.findById('5a96607b5ce650532494f011').exec((err, rs) => {if (err) {console.info("查詢失敗");console.info(err);} else {console.info("查詢成功");console.info(rs);let eatStr = rs.eat();console.info(eatStr); //骨頭,肉肉}});
  • 2、靜態方法
    靜態方法,是不需要實例化得到document,而是直接在model上調用的方法。
    所以,實例方法,是操作文檔(mongodb中的某一條記錄)數據用的,靜態方法是操作集合用的。

為animalSchema添加靜態方法:

//為model添加findDogs方法 animalSchema.statics.findDogs = function (backfun){this.find({title: /狗/}).exec(backfun); };

model調用:

animalModel.findDogs((err, rs) => {if (err) {console.info("查詢失敗");console.info(err);} else {console.info("查詢成功");console.info(rs); //打印出兩條狗的document}});

-3、查詢方法
擴展schema對象的query屬性,給model添加查詢方法,主要為了擴展query的個性化方法需要。

//為query添加findMonkey方法 animalSchema.query.findMonkey = function (backfun){this.find({title: /猴/}).exec(backfun); };

query調用:

let rsQuery = animalModel.find();rsQuery.findMonkey((err, rs) => {if (err) {console.info("查詢失敗");console.info(err);} else {console.info("查詢成功");console.info(rs); //打印出一只猴子的document}});

9、虛擬屬性

schema上除了可以設置方法以外,還可以設置虛擬屬性,就像vue的getter一樣,實際數據庫中沒有這個屬性,但可以通過虛擬屬性機制自定義一個經過處理的值,雖然用方法同樣能實現,但虛擬屬性效率更高。

//添加虛擬屬性nameAndSex animalSchema.virtual('info').get(function () {return this.title + "," +this.sex; });

調用:

animalModel.find({title: /狗/}).exec((err, rs) => {if (err) {console.info("查詢失敗");console.info(err);} else {console.info("查詢成功");rs.forEach( function (item, index, arr) {console.info(item.info);});}});

打印結果:

1號狗狗,male 2號狗狗,male

10、前置與后置鉤子

通過schema可以為指定的某些方法添加前置鉤子函數與后置鉤子函數。前置鉤子函數在指定方法開始前調用,后置鉤子函數不是在指定方法結束后操作,二是在指定方法開始前的最后一步操作。
前置鉤子是pre()
后置鉤子是post()

//為find方法指定前置操作1 animalSchema.pre('find', function (next) {console.info('前置操作1');next(); });//為find方法指定前置操作2 animalSchema.pre('find', function (next) {console.info('前置操作2');next(); });//為find方法指定后置操作1 animalSchema.post('find', function () {console.info('后置操作1'); });//為find方法指定后置操作2 animalSchema.post('find', function () {console.info('后置操作2'); });

調用find()方法

animalModel.find({title: /狗/}).exec((err, rs) => {if (err) {console.info("查詢失敗");console.info(err);} else {console.info("查詢成功");console.info(rs);}});

得到打印結果:

前置操作1 前置操作2 后置操作1 后置操作2 查詢成功 [ { food: [ [Object], [Object] ],_id: 5a96607b5ce650532494f011,title: '1號狗狗',sex: 'male',__v: 0 },{ food: [ [Object], [Object] ],_id: 5a96607b5ce650532494f014,title: '2號狗狗',sex: 'male',__v: 0 } ]

注意,前置鉤子中有一個next函數,如果方法內不調用next(),被設置前置鉤子的方法(比如find())執行到鉤子時不會繼續向下執行。

可以添加前后鉤子的方法有:

init validate save remove count find findOne findOneAndRemove findOneAndUpdate insertMany update

以上是mongoose的常用基本操作,還有索引、聚合等等操作需要積累補充。

總結

以上是生活随笔為你收集整理的mongoose操作mongodb的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。