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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

应用Mongoose开发MongoDB(2)模型(models)

發布時間:2025/5/22 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 应用Mongoose开发MongoDB(2)模型(models) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據模型及基礎操作模板

?

為了使工程結構清晰,將數據模型(Schema, Model)的建立與增刪查改的基礎操作模板寫在一起,命名為數據庫設計中的Collection(對應于關系型數據庫中的表定義)名,并存儲在models文件夾中。

?

Schema與Model的建立:

Schema是Mongoose里的數據模式,可以理解為表結構定義;每個Schema會映射到MongoDB中的一個Collection,不具備操作數據庫的能力。

考慮以下代碼:

//引入mongoose模塊 var mongoose = require('mongoose'); //以json對象形式定義Schema var taskSchema = new mongoose.Schema({userId: String,invalidFlag:Number,task: [{_id:0,type: {type:String},details:[{startTime : Date,frequencyTimes : Number,frequencyUnits : String,status:Number}]}], revisionInfo:{operationTime:Date,userId:String} }); //導出Model var taskModel = mongoose.model('task', taskSchema);

  


這就定義了一個Schema和Model,映射到MongoDB中的一個Collection。實際操作過程中,需要注意以下幾點:?

1. 命名規范:首字母小寫,如果命名中有多個單詞,第一個單詞首字母小寫,其他單詞首字母大寫。關于這一點,是本文這一系列的默認習慣規范,不同開發者有不同習慣。

2. 定義Schema時以json對象形式定義,鍵為屬性,值為屬性說明,關于屬性說明,至少需要定義屬性的類型(即type),如果有其他需要說明的,同樣以json的形式說明,鍵為屬性,值為說明。

3. Schema.Types: 可用的Schema Types有8種,其中String, Number, Date, Buffer, Boolean直接定義即可;Mixed, ObjectId需要引入mongoose模塊后定義;array使用中括號加元素Type定義,不說明也可以。Mixed類型可以看做嵌套類型,可以不指定內部元素的鍵,若需要指定內部元素的鍵,可以直接使用大括號聲明(如上的’revisionInfo’)

//引入mongoose模塊?
var mongoose = require('mongoose'); //以json對象形式定義Schema var taskSchema = new mongoose.Schema({_id: mongoose.Schema.Types.ObjectId, //主鍵doctor_id: {type: mongoose.Schema.Types.ObjectId, ref:’doctor’}, //外鍵鏈接到“doctor”content: mongoose.Schema.Types.Mixed //混合或嵌套類型 });

  

4. 在定義Schema時的其他操作:

a)???????? 對于全部Type有效:

required: boolean或function. 如果布爾值為真則會對模型進行驗證。

default: 設置屬性的默認值,可以是value或者function。

select: boolean 查詢時默認輸出該屬性。

validate: function, 對屬性進行自定義驗證器。

get, set: function, 自定義屬性的值

//get, set使用例子?
//參考: http://mongoosejs.com/docs/schematypes.html var numberSchema = new Schema({integerOnly: {type: Number,get: v => Math.round(v),set: v => Math.round(v)} });var Number = mongoose.model('Number', numberSchema);var doc = new Number(); doc.integerOnly = 2.001; doc.integerOnly; // 2

  

b)??????? 索引Indexes

index: Boolean 屬性是否索引

unique: Boolean 是否唯一索引

sparse: Boolean 是否稀疏索引:稀疏索引,如果索引鍵中存儲值為null,就跳過這個文檔,這些文檔將不會被索引到。不過查詢時默認是不使用稀疏索引的,需要使用hint()指定使用在模型中建立的稀疏索引。

c)???????? 對字符串String有效

lowercase: Boolean 轉成小寫,即對值調用.toLowerCase()

uppercase: Boolean 轉成大寫,即對值調用.toUpperCase()

trim: Boolean 去掉開頭和結尾的空格,即對值調用.trim()

match: 正則表達式,生成驗證器判斷值是否符合給定的正則表達式

enum: 數組,生成驗證器判斷值是否在給定的數組中

d)??????? 對數字Number或時間Date有效

min, max: Number或Date 生成驗證器判斷是否符合給定條件

5. 注意:

聲明Mixed類型時,以下幾種方式是等價的:

//引入mongoose模塊?
var mongoose = require('mongoose');//聲明Mixed類型 var Any = new Schema({ any: {} }); var Any = new Schema({ any: Object }); var Any = new Schema({ any: mongoose.Schema.Types.Mixed});

  

???????? 關于數組(Array):

a)???????? 聲明:

//引入mongoose模塊 var mongoose = require('mongoose');//聲明類型為Mixed的空數組 var Empty1 = new Schema({ any: [] }); var Empty2 = new Schema({ any: Array }); var Empty3 = new Schema({ any: [mongoose.Schema.Types.Mixed] }); var Empty4 = new Schema({ any: [{}] });

  


b)??????? 默認屬性:?

數組會隱式地含有默認值(default: []),要將這個默認值去掉,需要設定默認值(default: undefined)

如果數組被標記為(required: true),存入數據時該數組必須含有一個元素,否則會報錯。

6. 自定義Schema Type:

從mongoose.SchemaType繼承而來,加入相應的屬性到mongoose.Schema.Type中,可以使用cast()函數實現,具體例子參見:

http://mongoosejs.com/docs/customschematypes.html

7. Schema Options:對Schema進行的一系列操作,因為我沒有驗證過,就不細說了。

參考 http://mongoosejs.com/docs/guide.html

?

=========================================================================

在這個文件中,除了導出和編譯數據模型外,另外建立了數據庫增刪查改的基礎方法,生成函數,導出模塊供其他文件調用。

仍然以上文中的../models/task.js文件作為示例:

//設置collection同名函數,并導出模塊 function Task(task) {this.task = task; }//添加基本的增刪查改操作函數模板 //...module.exports = Task;

  

增:

Task.prototype.save = function(callback) {var task = this.task;var newTask = new taskModel(task);newTask.save(function(err, taskItem) {if (err) {return callback(err);}callback(null, taskItem);}); }

  

需要注意的是,數據庫文檔存儲方法是在Task原型鏈上修改,使用save()函數實現。在進行數據存儲的操作過程中,首先從原型對象生成實例,這里原型對象就是所要存儲的文檔。完成從原型對象生成實例的操作,使用new運算符實現,然而new運算符無法共享屬性和方法,save()函數恰恰是需要共享的方法,因此使用prototype來設置一個名為save()的函數作為文檔的通用方法。

刪:

與增加方法不同,刪除、查找及修改方法直接在Task增加方法,因為這些方法是對模型進行操作,而模型的方法已在node_modules/mongoose/lib/model.js內定義。

與刪除有關的方法:

//刪除第一個匹配conditions的文檔,要刪除所有,設置'justOne' = false

remove(conditions, [callback]);

//刪除第一個匹配conditions的文檔,會忽略justOne操作符

deleteOne(conditions, [callback]);

//刪除所有匹配conditions的文檔,會忽略justOne操作符

deleteMany(conditions, [callback]);

//實現MongoDB中的findAndModify remove命令,并將找到的文檔傳入callback中

//options: 'sort', 'maxTimeMS', 'select'

findOneAndRemove(conditions, [options], [callback]);

//以主鍵作為查詢條件刪除文檔,并將找到的文檔傳入callback中

findByIdAndRemove(id, [options], [callback]);

Task.removeOne = function(query, callback, opts) {?
var options = opts || {};taskModel.findOneAndRemove(query, options, function(err, task) {if (err) {return callback(err);}callback(null, task);}); };

  

這個例子中,將導出的函數取名為Task.removeOne(), 在傳入參數時,將[option]放到了最后,這樣做的本意,是因為實際應用時,options往往是空的,不需要傳入,這樣做就可以在寫controller時直接省略而不用空字符串占位。但事實上,在model.js中定義時,已經做了處理:conditions必須傳入,且不能為function, 當第二個參數options是function時,將這個function認為是callback, 并將options設置為undefined

if (arguments.length === 1 && typeof conditions === 'function') {?
var msg = 'Model.findOneAndRemove(): First argument must not be a function.\n\n'+ ' ' + this.modelName + '.findOneAndRemove(conditions, callback)\n'+ ' ' + this.modelName + '.findOneAndRemove(conditions)\n'+ ' ' + this.modelName + '.findOneAndRemove()\n';throw new TypeError(msg);}if (typeof options === 'function') {callback = options;options = undefined;}

  

改:

與修改有關的方法:

//更新文檔而不返回他們

//option: ‘upsert’: if true, 如果沒有匹配條件的文檔則新建

//option: ‘multi’: if true, 更新多文檔

//option: ‘runValidators’, if true, 在更新之前進行模型驗證

//option: ‘setDefaultsOnInsert’, 如果此操作符與’upsert’同時為true, 將schema中的默認值新建到新文檔中

//注意不要使用已存在的實例作為更新子句,有可能導致死循環

//注意更新子句中不要存在_id字段,因為MongoDB不允許這樣做

//使用update時,值會轉換成對應type, 但是defaults, setters, validators, middleware不會應用,如果要應用這些,應使用findOne()然后在回調函數里調用.save()函數

update(conditions, doc, [options], [callback]);

//忽略multi操作符,將所有符合conditions的文檔修改

updateMany(conditions, doc, [options], [callback]);

//忽略multi操作符,僅將第一個符合conditions的文檔修改

updateOne(conditions, doc, [options], [callback]);

//使用新文檔替換而不是修改

replaceOne(conditions, doc, [options], [callback]);

//找到匹配的文檔,并根據[update]更新文檔,將找到的文檔傳入[callback]

//option: ‘new’: if true,返回更新后的文檔

//’upsert’, ‘runValidators’, ‘setDefaultsOnInsert’, ’sort’, ‘select’等操作符也可用

findOneAndUpdate([conditions], [update], [options], [callback]);

//通過主鍵找到匹配的文檔,并根據[update]更新文檔,將找到的文檔傳入[callback]

findByIdAndUpdate(id, [update], [options], [callback]);

Task.updateOne = function(query, obj, callback, opts, populate) {
var options = opts || {};var populate = populate || '';taskModel.findOneAndUpdate(query, obj, options).populate(populate).exec(function(err, uptask) {if(err){return callback(err);}callback(null, uptask);}); };Task.update = function(query, obj, callback, opts, populate) {var options = opts || {};var populate = populate || '';taskModel.update(query, obj, options).populate(populate).exec(function(err, uptask) {if(err){return callback(err);}callback(null, uptask);}); };

  

與刪除方法不同,callback不傳入.update()或.findOneAndUpdate()中,而在之后調用了.exec()中傳入了一個回調函數,如果err有內容則返回err, 否則返回uptask,也就是MongoDB的返回。這樣的處理,可以不需要等待MongoDB的響應。

populate是聯表查詢時使用的參數,將在之后的內容提到。

?

查:

與查詢有關的方法:

//conditions會在命令發送前自動被轉成對應的SchemaTypes

find(conditions, [projection], [options], [callback]);

//通過_id查詢到一條文檔

findById(id, [projection], [options], [callback]);

//查詢一條文檔,如果condition = null or undefined, 會返回任意一條文檔

findOne([conditions], [projection], [options], [callback]);

Task.getOne = function(query, callback, opts, fields, populate) {?
var options = opts || {};var fields = fields || null;var populate = populate || '';taskModel.findOne(query, fields, opts).populate(populate).exec(function(err, taskInfo) {if(err){return callback(err);}callback(null, taskInfo);}); };Task.getSome = function(query, callback, opts, fields, populate) {var options = opts || {};var fields = fields || null;var populate = populate || '';taskModel.find(query, fields, options).populate(populate).exec(function(err, tasks) {if(err) {return callback(err);}callback(null, tasks);}); };

  

在構造出的.getOne()和.getSome()函數的傳入參數中,可以看到option, field, populate在callback后面,因為最基本的情況是只有query和callback傳入,而后面的較少用到。而在一些要求復雜的查詢中,這三者是必不可少的。

雖然查詢最為復雜,不過都是通過.find()與.findOne()與各種操作符組合而成。同樣因為最基本的參數是condition與callback, 因此在導出函數時將這兩個參數放在最前面。值得注意的是,當查詢不到文檔時,.findOne()返回null, .find()返回空數組,這使得在調用getOne()函數時的某些情況下需要進行必要的輸出驗證,否則會報錯引起程序崩潰。

轉載于:https://www.cnblogs.com/gyjerry/p/6860466.html

總結

以上是生活随笔為你收集整理的应用Mongoose开发MongoDB(2)模型(models)的全部內容,希望文章能夠幫你解決所遇到的問題。

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