Mongoose学习

Mongoose学习

1. 说明

因为网上关于mongoose的文档有很多,但是都是分块的没有系统的总结,所以我总结网上的文章理出来一条思路,文档中的很多内容都是从其他文章中复制过来的,只作为个人知识的学习,不会用于商用,在文章多处我也注明了出处

2. Mongoose介绍

2.1. 什么是MongoDB?

MongoDB是一个开源的NoSQL数据库,相比MySQL那样的关系型数据库,它更为轻巧、灵活,非常适合在数据规模很大、事务性不强的场合下使用。

2.2. 什么是Mongoose?

Mongoose是封装了MongoDB的操作的一个对象模型库,为nodejs而生。就好像我们嫌原生javascript难写,代码量多,于是用jQuery库一样,因为MongoDB的操作接口复杂,不人性,所以有了Mongoose。这个库完全是可选的。

2.3. 名词解释

  • Schema:一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
  • Model:由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
  • Entity:由Model创建的实体,他的操作也会影响数据库

2.4. 注意

  • Schema、Model、Entity的关系请牢记,Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。

2.5. 学习文章

3. Schema

3.1. Schema.Type

  • 内置类型

    String Number Date Buffer Boolean Mixed Objectid Array

  • 用法实例

var schema = new Schema({
  name:    String,
  binary:  Buffer,
  living:  Boolean,
  updated: { type: Date, default: Date.now },
  age:     { type: Number, min: 18, max: 65 },
  mixed:   Schema.Types.Mixed,
  _someId: Schema.Types.ObjectId,
  array:      [],
  ofString:   [String],
  ofNumber:   [Number],
  ofDates:    [Date],
  ofBuffer:   [Buffer],
  ofBoolean:  [Boolean],
  ofMixed:    [Schema.Types.Mixed],
  ofObjectId: [Schema.Types.ObjectId],
  nested: {
    stuff: { type: String, lowercase: true, trim: true }
  }
})

// example use

var Thing = mongoose.model('Thing', schema);

var m = new Thing;
m.name = 'Statue of Liberty';
m.age = 125;
m.updated = new Date;
m.binary = new Buffer(0);
m.living = false;
m.mixed = { any: { thing: 'i want' } };
m.markModified('mixed');
m._someId = new mongoose.Types.ObjectId;
m.array.push(1);
m.ofString.push("strings!");
m.ofNumber.unshift(1,2,3,4);
m.ofDates.addToSet(new Date);
m.ofBuffer.pop();
m.ofMixed = [1, [], 'three', { four: 5 }];
m.nested.stuff = 'good';
m.save(callback);

3.2. Validation(验证)

  • Validation是在SchemaType定义
  • Validation是中间件的内部组件
  • Validation发生在document试图在默认值应用之后保存的时候。
  • Validation不在未定义的值运行,唯一例外是必要的验证器。
  • Validation是异步递归的,当你调用Model#save,子文档验证也会执行。如果发生错误,Model#save回调会接收它。
  • 验证支持完全定制

3.2.1. 内置校验器

  • 所有SchemaTypes都有内置requiredValidation。
  • 数字有最大值和最小值验证。
  • 字符串有枚举、匹配、最大长度和最小长度验证。
  • 用法实例
var schema = new mongoose.Schema({
    name:{
        type:'String',
        required: true,
        maxlength: 10,
        match: /^a/   
    },
    date: {
        type: Date,
        default: Date.now
    },
    age:{
        type:'Number',
        min:18,       //年龄最小18
        max:120     //年龄最大120
    },
    city:{
        type:'String',
        enum:['北京','上海']  //只能是北京、上海人
    },
});

3.2.2. 自定义校验器

  • 如果内置验证器不够,validation能够完全可以满足你的需求
  • 用法实例
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!'
    }
  }
});

var User = mongoose.model('user', userSchema);

var u = new User();

u.phone = '555.0123';
// Prints "ValidationError: 555.0123 is not a valid phone number!"
console.log(u.validateSync().toString());

u.phone = '201-555-0123';
// Prints undefined - validation succeeded!
console.log(u.validateSync());

3.3. 创建

  • 语法:mongoose.model(modelName, schema)
  • 用法实例
var Blog = mongoose.model('Blog', blogSchema)

3.4. 实例方法

  • 用法实例
// define a schema
var animalSchema = new Schema({ name: String, type: String });

// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function (cb) {
  return this.model('Animal').find({ type: this.type }, cb);
}
var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' });

dog.findSimilarTypes(function (err, dogs) {
  console.log(dogs); // woof
});

3.5. 静态方法

  • 用法实例
// assign a function to the "statics" object of our 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);
});

3.6. 索引

  • MongoDB支持二级索引。在mongoose,at the path level或schema层次定义Schema的索引。当创建复合索引时,在shema定义索引是必要的。
var animalSchema = new Schema({
  name: String,
  type: String,
  tags: { type: [String], index: true } // field level
});

animalSchema.index({ name: 1, type: -1 }); // schema level
  • 当程序启动时,Mongoose为每个在schema定义的索引自动地调用ensureIndex 。Mongoose会连续为每个索引调用ensureIndex,当所有ensureIndex调用成功或发生错误在model发出index事件。建议在生产中禁止这种行为因为索引创建能够导致显著的性能影响。通过给schema设置autoIndex选项为false来禁用行为,或者在connection全局设置选项config.autoIndex为false。
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });

3.7. Virtuals(虚拟属性)

  • virtual是你能 get 和 set 但不能保存到MongoDB的document属性。getter用于格式化或符合的field,而setter用于de-composing一个单值到多值存储。
  • 用法实例
// define a schema
var personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

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

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

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

console.log('%s is insane', bad.name.full); // Walter White is insane
bad.name.full = 'Breaking Bad';

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

3.8. option(扩展选项)

  • 用法实例
new Schema({..}, options);

// or

var schema = new Schema({..});
schema.set(option, value);

3.9. Middleware(中间件)

  • 中间件(也称为pre and post hook)是执行异步函数期间传递控制权的函数。中间件在schema级别上被指定并对于编写插件非常有用

3.9.1. document中间件和query中间件

  • document中间件支持以下document函数

    • init
    • validate
    • save
    • remove
  • query中间件支持以下model和query函数

    • count
    • find
    • findOne
    • findOneAndRemove
    • findOneAndUpdate
    • update
  • 注意:没有对remove()的query hook,只有对document的。如果你设置了一个remove hook,执行myDoc.remove()时它会激活,而不是执行MyModel.remove()。

3.9.2. pre类型中间件

3.9.3. post类型中间件

3.10. Plugins(插件)

  • schema是可插入的,即,它们可以应用预包装的能力,从而扩展其功能。这是一个非常强大的功能。

4. Model

5. Document

5.1. Population(join)

  • http://www.cnblogs.com/surahe/p/5188211.html
  • population是自动将document中指定path替换为其他collection的document的过程。我们能迁移document、多个document、简单对象、多个简单对象或者是查询返回的所有对象。

5.2. Sub-Docs(子文档)

6. CURD

6.1. 连接

var mongoose = require('mongoose');    //引用mongoose模块
var db = mongoose.createConnection('localhost','test'); //创建一个数据库连接
  • 打开本机localhost的test数据库时,我们可以监测是否有异常
db.on('error',console.error.bind(console,'连接错误:'));
db.once('open',function(){
  //一次打开记录
});

6.2. 创建

6.2.1. document保存

var Tank = mongoose.model('Tank', yourSchema);

var small = new Tank({ size: 'small' });
small.save(function (err) {
  if (err) return handleError(err);
  // saved!
})

6.2.2. model保存

  • 语法

180108_PxJD_1416844.jpg

  • 该方法既可以存储一条数据也可以存储多条数据
  • 如果有回调函数,那么在存储多条数据的时候如果有一条报错了,那么不会走promise的then方法,但是其他没有报错的数据已经被插入了
  • 如果没有回调函数,那么在存储多条数据的时候如果有一条报错了,那么会走promise的then方法,但是其他没有报错的数据已经被插入了
Model.create({ size: 'small' }, function (err, doc) {
  if (err) return handleError(err);
  // saved!
})

const promise= Model.create(Doc)
promise.then(function (result) {
    console.log(1111111111)
    console.log(result)
},function (err) {
    console.log(2222222222)
    console.log(err)
})

6.3. 修改

6.3.1. 修改不返回document

  • 语法:Model.update(conditions, doc, [options], [callback])
  • 用法实例
Tank.update({ _id: id }, { $set: { size: 'large' }}, function (err, raw) {
    if (err) return handleError(err);
    console.log('The raw response from Mongo was ', raw);
});

6.3.2. 修改返回document

  • 写法一
Tank.findById(id, function (err, tank) {
  if (err) return handleError(err);

  tank.size = 'large';
  tank.save(function (err) {
    if (err) return handleError(err);
    res.send(tank);
  });
});
  • 写法二(推荐)
Tank.findByIdAndUpdate(id, { $set: { size: 'large' }}, function (err, tank) {
  if (err) return handleError(err);
  res.send(tank);
});

6.4. 删除

Tank.remove({ size: 'large' }, function (err) {
  if (err) return handleError(err);
  // removed!
});

6.5. 查询

6.5.1. 直接查询

  • 在查询时带有回调函数的,称之为直接查询,查询的条件往往通过API来设定
  • 用法实例
 PersonModel.findOne({'name.last':'dragon'},'some select',function(err,person){
      //如果err==null,则person就能取到数据
    });

6.5.2. 链式查询

6.5.2.1. 写法一
  • 这种方式相对直接查询,分的比较明细,如果不带callback,则返回query,query没有执行的预编译查询语句,该query对象执行的方法都将返回自己,只有在执行exec方法时才执行查询,而且必须有回调。
  • 用法实例
 var query = PersonModel.findOne({'name.last':'dragon'});
     query.select('some select');
     query.exec(function(err,pserson){
     //如果err==null,则person就能取到数据
  });

 

6.5.2.2. 写法一
  • 用法实例
Person
      .find({ occupation: /host/ })
      .where('name.last').equals('Ghost')
      .where('age').gt(17).lt(66)
      .where('likes').in(['vaporizing', 'talking'])
      .limit(10)
      .sort('-occupation')
      .select('name occupation')
      .exec(callback);

 

免责说明

1、本博客中的文章摘自网上的众多博客,仅作为自己知识的补充和整理,并分享给其他需要的coder,不会用于商用。

2、因为很多博客的地址看完没有及时做保存,所以很多不会在这里标明出处,非常感谢各位大牛的分享,也希望大家理解。

 

转载于:https://my.oschina.net/u/1416844/blog/849736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值