原文出處html
SQL術語/概念 | MongoDB術語/概念 | 解釋/說明 |
---|---|---|
rdatabase | database | - |
table | collection | 數據庫表/集合 |
row | document | 數據記錄行/文檔 |
column | index | 數據記錄行/文檔 |
table joins | - | 錶鏈接,MongoDB不支持 |
primary key | primary key 主鍵 | MongoDB自動將_id字段設置爲主鍵 |
mongoose中任何任何事物都是從Schema開始的。每個Schema對應MongoDB中的一個集合(collection)。Schema中定義了集合中文檔(document)的樣式。node
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var blogSchema = new Schema({ title: String, author: String, body: String, comments: [{ body: String, date: Date }], date: { type: Date, default: Date.now }, hidden: Boolean, meta: { votes: Number, favs: Number } });
若是以後想要在Schema中添加鍵,可使用Schema#add方法。mongodb
爲了使用schema定義,咱們須要轉換blogSchema爲一個Model。使用數據庫
mongoose.model(modelName, schema) var BlogModel = mongoose.model('Blog', blogSchema);// 開始吧!
Model的實例是document。實例有不少內置的方法,咱們也能夠給實例自定義方法。api
var animalSchema = new Schema({ name: String, type: String }); animalSchema.methods.findSimilarTypes = function (cb) { return this.model('Animal').find({ type: this.type }, cb); }
如今全部的動物實例有findSimilarTypes方法。數組
var AnimalModel = mongoose.model('Animal', animalSechema); var dog = new AnimalModel({ type: 'dog' }); dog.findSimilarTypes(function (err, dogs) { console.log(dogs); // woof });
重寫一個默認的實例方法可能會致使不期待的結果。安全
給Model添加一個靜態方法也是簡單的。app
animalSchema.statics.findByName = function (name, cb) { this.find({ name: new RegExp(name, 'i') }, cb); } var AnimalModel = mongoose.model('Animal', animalSchema); AnimalModel.findByName('fido', function (err, animals) { console.log(animals); });
區別就是一個給Model添加方法(statics),
一個給實例添加方法(methods)。mongoose
MongoDB支持二級索引,定義索引有兩種方式分佈式
路徑級別 schema級別
var animalSchema = new Schema({ name: String, type: String, tags: { type: [String], index: true } // field level }); animalSchema.index({ name: 1, type: -1 }); // schema level, 1是正序,-1是倒序
若是要創建複合索引的話,在schema級別創建是必要的。
索引或者複合索引能讓搜索更加高效,默認索引就是主鍵索引ObjectId,屬性名爲_id。
數據庫中主要的就是CRUD操做,創建索引能夠提升查詢速度。可是過多的索引會下降CUD操做。深度好文以下
http://www.cnblogs.com/huangx...
Schema中若是定義了虛擬屬性,那麼該屬性將不寫入數據庫。寫入數據庫的仍是原來的屬性。
// 定義一個schema var personSchema = new Schema({ name: { first: String, last: String } }); // 編譯 var Person = mongoose.model('Person', personSchema);// 創造實例 var bad = new Person({ name: { first: 'Walter', last: 'White' } });
咱們將名字分紅名字和姓,若是要獲得全名,咱們須要
console.log(bad.name.first + ' ' + bad.name.last); // Walter White
這樣無疑是麻煩的,咱們能夠經過虛擬屬性的getter來解決這個問題。
personSchema.virtual('name.full').get(function () { return this.name.first + ' ' + this.name.last; });
那麼就可使用bad.name.full直接調用全名了。
反之,若是咱們知道虛擬屬性name.full,經過setter也能夠獲得組成name.full的每一項。
personSchema.virtual('name.full').set(function (name) { var split = name.split(' '); this.name.first = split[0]; this.name.last = split[1]; }); ... mad.name.full = 'Breaking Bad'; console.log(mad.name.first); // Breaking console.log(mad.name.last); // Bad
schema有一些配置項可使用,有兩種方式:
new Schema({…}, options) var schema = new Schema({...}); schema.set(option, value);
有效的配置有:
應用開始的時候,Mongoose對每個索引起送一個ensureIndex的命令。索引默認(_id)被Mongoose建立。
當咱們不須要設置索引的時候,就能夠經過設置這個選項。
var schema = new Schema({..}, { autoIndex: false }); var Clock = mongoose.model('Clock', schema); Clock.ensureIndexes(callback);
彷佛是說這個(mongoose buffer)管理在mongoose鏈接關閉的時候重連,若是取消buffer設置,以下:(存疑)
var schema = new Schema({..}, { bufferCommands: false });
若是有數據庫的批量操做,該屬性能限制一次操做的量,例如:
new Schema({...},{capped:1024}); //一次操做上線1024條數據
固然該參數也但是對象,包含size、max、autiIndexId屬性
new Schema({...},{capped:{size:1024,max:100,autoIndexId:true}});
在MongDB中默認使用Model的名字做爲集合的名字,如過須要自定義集合的名字,能夠經過設置這個選項。
var schema = new Schema({...}, {collection: 'yourName'});
mongoose分配給每個schema一個虛擬屬性id,它是一個getter。返回的是_id轉換爲字符串後的值。若是不須要爲schema添加這個getter,能夠經過id配置修改。
// 默認行爲 var pageSchema = new Schema({ name: String }); var pageModel = mongoose.model('Page', pageSchema); var p = new pageModel({ name: 'mongodb.org' }); console.log(p.id); // '50341373e894ad16347efe01' // 禁止id var pageSchema = new Schema({ name: String }, { id: false } ); var pageModel = mongoose.model('Page', pageSchema); var p = new pageModel({ name: 'mongodb.org' }); console.log(p.id); // undefined
在一個schema中若是沒有定義_id域(field),那麼mongoose將會默認分配一個_id域(field)。類型是ObjectId。若是不須要使用這個默認的選擇,能夠經過設置這個選項。
經過在schema中設置這個字段能夠阻止生成mongoose得到_id。可是在插入的時候仍然會生成_id。設置這個字段以後,若是再使用Schema.set(’_id’, false)將無效。
// 默認行爲 var pageSchema = new Schema({ name: String }); var pageModel = mongoose.model('Page', pageSchema); var p = new pageModel({ name: 'mongodb.org' }); console.log(p); // { _id: '50341373e894ad16347efe01', name: 'mongodb.org' } // 禁用 _id var pageSchema = new Schema({ name: String }, { _id: false }); // schema構造器設置以後,不要再像下面這樣設置 // var schema = new Schema({ name: String }); // schema.set('_id', false); var PageModel = mongoose.model('Page', pageSchema); var p = new pageModel({ name: 'mongodb.org' }); console.log(p); // { name: 'mongodb.org' } // 當插入的時候,MongoDB將會建立_id p.save(function (err) { if (err) return handleError(err); pageModel.findById(p, function (err, doc) { if (err) return handleError(err); console.log(doc); // { name: 'mongodb.org', _id: '50341373e894ad16347efe12' } }) })
爲何不建議使用set
容許在schema級別設置query#read,對於全部的查詢,提供給咱們一種方法應用默認的ReadPreferences。
這個配置會在MongoDB全部的操做中起做用。若是設置成true就是在操做的時候要等待返回的MongoDB返回的結果,好比update,要返回影響的條數,才日後執行,若是safe:false,則表示不用等到結果就向後執行了。
默認設置爲true能保證全部的錯誤能經過咱們寫的回調函數。咱們也能設置其它的安全等級如:
{ j: 1, w: 2, wtimeout: 10000 }
表示若是10秒內寫操做沒有完成,將會超時。
關於j和w,這裏有很好的解釋。
http://kyfxbl.iteye.com/blog/...
須要mongodb作分佈式,纔會使用該屬性。
默認是enabled,若是實例中的域(field)在schema中不存在,那麼這個域不會被插入到數據庫。
var ThingSchema = new Schema({a:String}); var ThingModel = db.model('Thing',SchemaSchema); var thing = new Thing({iAmNotInTheThingSchema:true}); thing.save();//iAmNotInTheThingSchema這個屬性將沒法被存儲 // 經過doc.set()設置也會受到影響。 var thingSchema = new Schema({..}) var Thing = mongoose.model('Thing', thingSchema); var thing = new Thing; thing.set('iAmNotInTheSchema', true); thing.save(); // iAmNotInTheSchema is not saved to the db
若是取消嚴格選項,iAmNotInTheThingSchema將會被存入數據庫
var thingSchema = new Schema({..}, { strict: false }); var thing = new Thing({ iAmNotInTheSchema: true }); thing.save(); // iAmNotInTheSchema is now saved to the db!!
該選項也能夠在Model級別使用,經過設置第二個參數,例如:
var ThingModel = db.model('Thing'); var thing1 = new ThingModel(doc,true); //啓用嚴格 var thing2 = new ThingModel(doc,false); //禁用嚴格
strict也能夠設置爲throw,表示出現問題將會拋出錯誤而不是拋棄不合適的數據。
注意:
在mongoose v2裏默認是false。
在實例上設置的任何鍵值對若是再schema中不存在對應的,將會被忽視。
var thingSchema = new Schema({..}) var Thing = mongoose.model('Thing', thingSchema); var thing = new Thing; thing.iAmNotInTheSchema = true; thing.save(); // iAmNotInTheSchema 不會保存到數據庫。
和toObject相似,選擇這個選項爲true後,可是隻有當實例調用了toJSON方法後,纔會起做用。
var schema = new Schema({ name: String }); schema.path('name').get(function (v) { return v + ' is my name'; }); schema.set('toJSON', { getters: true, virtuals: false }); var M = mongoose.model('Person', schema); var m = new M({ name: 'Max Headroom' }); console.log(m.toObject()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' } console.log(m.toJSON()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' } console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }
能夠看出,配置屬性name對toObject沒影響,對toJSON有影響。
選擇這個選項爲true後,默認對這個schema全部的實例都有做用。不須要實例手動調用。
var schema = new Schema({ name: String }); schema.path('name').get(function (v) { return v + ' is my name'; }); schema.set('toObject', { getters: true }); var M = mongoose.model('Person', schema); var m = new M({ name: 'Max Headroom' }); console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
較上面不一樣的是,沒有virtuals: false這個設置。
在mongoose裏,若是schema裏有個對象,而且這個對象有個type鍵,mongoose將會將這個做爲一種類型聲明。
// Mongoose 認爲loc字段的類型是一個字符串,而不是有type這個字段 var schema = new Schema({ loc: { type: String, coordinates: [Number] } });
然而,對於一些應用來講,type字段是必要的。那麼能夠經過typeKey來設置。
var schema = new Schema({ // Mongoose 這時候認爲loc字段有兩個鍵,一個是type,一個是coordinates loc: { type: String, coordinates: [Number] }, // Mongoose 這時候認爲name字段的類型是字符串。 name: { $type: String } },{ typeKey: '$type' }); // '$type'鍵意味着這是一個類型宣告,而不是默認的type
默認得,文檔被保存到數據庫的時候會自動驗證,這是爲了防止無效的文檔。若是想要手動處理驗證,而且能保存不經過驗證的文檔,能夠設置這個選項爲false。
var schema = new Schema({ name: String }); schema.set('validateBeforeSave', false); schema.path('name').validate(function (value) { return v != null; }); var M = mongoose.model('Person', schema); var m = new M({ name: null }); m.validate(function(err) { console.log(err); // 將會告訴你null不被容許 }); m.save(); // 儘管數據無效,可是仍然能夠保存。
版本鎖設置在每個文檔(document)上,由mogoose生成。默認的值是__v,可是能夠自定義。
var schema = new Schema({ name: 'string' }); var Thing = mongoose.model('Thing', schema); var thing = new Thing({ name: 'mongoose v3' }); thing.save(); // { __v: 0, name: 'mongoose v3' } // 自定義版本鎖 new Schema({..}, { versionKey: '_somethingElse' }); var Thing = mongoose.model('Thing', schema); var thing = new Thing({ name: 'mongoose v3' }); thing.save(); // { _somethingElse: 0, name: 'mongoose v3' }
不要將這個選項設置爲false除非你知道你在作什麼。
http://aaronheckmann.tumblr.c...
按照這裏的說法,大體是說,加入在一個博客系統中,一我的全部的評論是一個數組,那麼全部的評論是有索引的,好比某一條評論的body,comments.3.body,這裏3是索引。假如一個評論者(A)想要修改本身的評論,可是此時另外一個評論者(B)刪除(或其餘操做)了本身的評論,那麼對A的索引可能會形成變化,此時對A的操做會發生錯誤。
爲了改變這個問題,mongoose v3添加了version key配置。不管何時修改一個數組潛在地改變數組元素位置,這個version key(__V)的值會加1。在where條件中也須要添加__v條件,若是能經過(數組索引沒改變),就能夠修改,例如:
posts.update( { _id: postId, __v: verionNumber } , { $set: { 'comments.3.body': updatedText }} );
若是在更新以前刪除了評論,那麼就會發生錯誤。
post.save(function (err) { console.log(err); // Error: No matching document found. });
若是在schema設置這個選項,createdAt和updatedAt域將會被自動添加的文檔中。它們默認的類型是Date,默認的名字是createdAt和updatedAt,不過咱們能夠本身修改。
var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } }); var Thing = mongoose.model('Thing', thingSchema); var thing = new Thing(); thing.save(); // created_at & updatedAt將會被包含在文檔。
在mongoos 4, update()和findOneAndUpdate()方法只檢查頂級schema的strict的選項設置。
var childSchema = new Schema({}, { strict: false });// 這裏parentSchema是topSchema,而childSchema是subSchema。 var parentSchema = new Schema({ child: childSchema }, { strict: 'throw' }); var Parent = mongoose.model('Parent', parentSchema); Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) { // 發生錯誤由於parentSchema設置了strict: 'throw'} // 即便childSchema設置了{strict: false} }); var update = { 'child.name': 'Luke Skywalker' }; var opts = { strict: false }; Parent.update({}, update, opts, function(error) { // 這個能夠經過由於重寫了parentSchema的strict選項 });
若是設置了useNestedStrict爲true,mogoose在更新時使用childSchema的strict選項。
var childSchema = new Schema({}, { strict: false }); var parentSchema = new Schema({ child: childSchema }, { strict: 'throw', useNestedStrict: true }); var Parent = mongoose.model('Parent', parentSchema); Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) { // 能夠更新 });
默認得,mongoose會轉換實體中鍵的順序。好比
new Model({ first: 1, second: 2 })
將會在MongoDB中存儲爲{ second: 2, first: 1 };這帶來了極大的不方便。
Mongoose v4.6.4 有一個retainKeyOrder選項確保mongoose不會改變鍵的順序。
參考
http://cnodejs.org/topic/504b...