深刻淺出mongoose

mongoose是nodeJS提供鏈接 mongodb的一個庫,相似於jquery和js的關係,對mongodb一些原生方法進行了封裝以及優化。簡單的說,Mongoose就是對node環境中MongoDB數據庫操做的封裝,一個對象模型工具,將數據庫中的數據轉換爲JavaScript對象以供咱們在應用中使用。html

install mongoose

npm install mongoose --save
複製代碼
const mongoose = require('mongoose'),
      connection = mongoose.connect('mongodb://127.0.0.1:27017/wechatShop', {
        useMongoClient: true
      });
複製代碼

Schema

Mongoose的一切都始於一個Schema。每一個schema映射到MongoDB的集合(collection)和定義該集合(collection)中的文檔的形式。 Schemas不只定義了文檔和屬性的結構,還定義了文檔實例方法、靜態模型方法、複合索引和文檔被稱爲中間件的生命週期鉤子。node

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
  }
});
複製代碼

Models

使用咱們的schema定義,咱們須要將咱們的blogschema轉成咱們能夠用的模型。爲此,咱們經過mongoose.model(modelName, schema)。python

var Blog = mongoose.model('Blog', blogSchema);
複製代碼

實例方法

模型的實例是文檔(documents)。文檔有許多本身內置的實例方法。咱們也能夠定義咱們本身的自定義文檔實例方法。mysql

var Blog = mongoose.model('Blog', blogSchema);
var blog = new Schema({ name: String, type: String });//模型實例
複製代碼

經常使用的內置實例方法有:jquery

remove、set、get、invalidate、populate、save等git

詳細api可查閱官方文檔內置的實例方法github

下面咱們來講說自定義實例方法。自定義實例方法,就是對當前實例的methods擴展方法便可,以下所示:sql

animalSchema.methods.findSimilarTypes = function(cb) {
  return this.model('Animal').find({ type: this.type }, cb);
};
複製代碼

靜態方法

經常使用的內置靜態方法有:mongodb

create、find、findOne等數據庫

給一個模型添加靜態方法的也是很簡單。繼續咱們的animalschema:

animalSchema.statics.findByName = function(name, cb) {
  return this.find({ name: new RegExp(name, 'i') }, cb);
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function(err, animals) {
  console.log(animals);
});
複製代碼

查詢助手

您還能夠像實例方法那樣添加查詢輔助功能,這是,但對於mongoose的查詢。查詢輔助方法可讓你擴展mongoose鏈式查詢生成器API。

animalSchema.query.byName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.find().byName('fido').exec(function(err, animals) {
  console.log(animals);
});
複製代碼

索引

mongoose一樣也對索引作了處理,在mongoose中定義索引有兩種方法。

第一種:直接在schema裏面定義,以下所示

var User = mongoose.model('User', {
  username: {
      type: String,
      index: true
  },
  password: String
})
複製代碼

第二種:統必定義索引

var User = mongoose.model('User', {
  username: {
      type: String
  },
  password: String
});

User.index({
    username: 1 / -1  (正向和逆向)
})
複製代碼

關閉索引:

mongoose.connect('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } });
// or  
mongoose.createConnection('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } });
// or
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });
複製代碼

注意:索引濫用會致使很嚴重的性能問題,建議合理使用索引。

虛擬屬性(針對實例即文檔)

虛擬屬性 是文檔屬性,您能夠獲取和設置但不保存到MongoDB。用於格式化或組合字段,從而制定者去組成一個單一的值爲存儲多個值是有用的。

下面咱們先定義一個實例

// define a schema
var personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

// compile our model
var Person = mongoose.model('Person', personSchema);

// create a document
var bad = new Person({
    name: { first: 'Walter', last: 'White' }
});
複製代碼

假設咱們想打印bad的全名。咱們能夠這樣作:

console.log(bad.name.first + ' ' + bad.name.last); // Walter White
複製代碼

或者咱們能夠在personschema定義 虛擬屬性的getter ,這樣咱們不須要每次寫出這個字符串的拼接:

personSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});

console.log('%s is insane', bad.name.full); // Walter White is insane
複製代碼

注意,這裏的虛擬屬性並無存入數據庫,因此若是是直接獲取,是獲取不到值的。

驗證

在咱們進入驗證語法的細節以前,請記住如下的規則:

驗證是在SchemaType定義

驗證是中間件。Mongoose寄存器驗證做爲pre('save')鉤子在每一個模式默認狀況下。

你能夠手動使用doc運行驗證。validate(callback) or doc.validateSync()。

驗證程序不運行在未定義的值上。惟一的例外是required驗證器。

驗證異步遞歸;當你調用Model#save,子文檔驗證也能夠執行。若是出現錯誤,你的 Model#save回調接收它。

驗證是可定製的。

var schema = new Schema({
      name: {
        type: String,
        required: true
      }
    });
    var Cat = db.model('Cat', schema);

    // This cat has no name :(
    var cat = new Cat();
    cat.save(function(error) {
      assert.equal(error.errors['name'].message,
        'Path `name` is required.');

      error = cat.validateSync();
      assert.equal(error.errors['name'].message,
        'Path `name` is required.');
    });
複製代碼
Mongoose有幾個內置驗證器。

全部的schematypes有內置的require驗證器。所需的驗證器使用SchemaType的checkrequired()函數肯定的值知足所需的驗證器。

數值( Numbers )有最大(man)和最小(min)的驗證器。

字符串(String)有枚舉,match,maxLength和minLength驗證器。

每個上述的驗證連接提供更多的信息關於如何使他們和自定義錯誤信息。

var breakfastSchema = new Schema({
      eggs: {
        type: Number,
        min: [6, 'Too few eggs'],
        max: 12
      },
      bacon: {
        type: Number,
        required: [true, 'Why no bacon?']
      },
      drink: {
        type: String,
        enum: ['Coffee', 'Tea']
      }
    });
    var Breakfast = db.model('Breakfast', breakfastSchema);

    var badBreakfast = new Breakfast({
      eggs: 2,
      bacon: 0,
      drink: 'Milk'
    });
    var error = badBreakfast.validateSync();
    assert.equal(error.errors['eggs'].message,
      'Too few eggs');
    assert.ok(!error.errors['bacon']);
    assert.equal(error.errors['drink'].message,
      '`Milk` is not a valid enum value for path `drink`.');

    badBreakfast.bacon = null;
    error = badBreakfast.validateSync();
    assert.equal(error.errors['bacon'].message, 'Why no bacon?');
複製代碼
自定義驗證

若是內置驗證器是不夠的話,你能夠自定義驗證器來適應你的需求。

var userSchema = new Schema({
      phone: {
        type: String,
        validate: {
          validator: function(v) {
            return /\d{3}-\d{3}-\d{4}/.test(v);
          },
          message: '{VALUE} is not a valid phone number!'
        },
        required: [true, 'User phone number required']
      }
    });
複製代碼
驗證的錯誤處理

驗證失敗後Errors返回一個錯誤的對象其實是validatorerror對象。每一個ValidatorError有kind, path, value, and message屬性。

var Person = db.model('Person', personSchema);
var person = new Person();

var error = person.validateSync();
複製代碼

聯表

若是你使用過mysql,確定用過join,用來聯表查詢,但mongoose中並無join,不過它提供了一種更方便快捷的辦法,Population。

首先定義兩個model。

var User = mongoose.model('User', {
  username: String,
  password: String
})

var News = mongoose.model('News', {
  title: String,
  author: {
    type: mongoose.Schema.ObjectId,
    ref: 'User'
  }
});
複製代碼

而後添加數據

User.create({username:'ck',username:'滴滴'},function(err, data){
  console.log(data)
  News.create({title:'title',author:data},function(){

  })
})
複製代碼

打印查詢結果到控制檯

News.findOne().populate('author','username').exec(function(err, doc){
  console.log('==============',err, doc)
  //    ============== null { _id: 5a41d2e16f78a43c5873fe03,
  //    title: 'title',
  //    author: { _id: 5a41d2e16f78a43c5873fe02, username: 'ck' 
  //    },
  //    __v: 0 }
})
複製代碼
歡迎各路大佬對文章錯誤的地方進行指正,萬分感謝,共同窗習進步。博主的GitHub地址,能夠在GitHub提Issues或者直接在文章下面評論區留言。
相關文章
相關標籤/搜索