【转载】深入浅出mongoose
2018-01-11 16:32
211 查看
深入浅出mongoose
原文在此:http://blog.csdn.net/zhalcie2011/article/details/71750915,由于不知道什么原因,原文配色不对,白字白底,基本没有可读性,重新编辑转帖方便自己阅读。mongoose是nodeJS提供连接mongodb的一个库.此外还有mongoskin,mongodb(mongodb官方出品).本人,还是比较青睐mongoose的,因为他遵循的是一种,模板式方法,能够对你输入的数据进行自动处理.有兴趣的同学可以去
初入mongoose
installmongoose
I’vesaidthat.使用mongoose你需要有nodeJS和mongodb数据库.这两个东西,前端宝宝们应该很清楚了》下载mongoose:npminstallmongoose--save
connectmongoose
下载好数据库之后,我们来碰碰运气,看你能不能连接上database.首先,打开你的mongodb;mongod;//这里我已经将mongodb放在环境变量中了
数据库成功打开后:在js文件中写入:
'usestrict'; constmongoose=require('mongoose'); mongoose.connect('mongodb://localhost:27017/test'); constcon=mongoose.connection; con.on('error',console.error.bind(console,'连接数据库失败')); con.once('open',()=>{ //成功连接 })
(其实,懂得童鞋,你只要copy就行了.)OK,运气好的同学,此刻嘴角扬起45°的微笑.运气差的同学,出门左转google.简单连接mongoose后,我们来看一看mongoose的基本构造吧.
understandmongoose
mongoose实际上,可以说是Oracle和mongodb的一个混合产物,但归根接地还是mongodb的.这里我要祭出,我珍藏很久的对比图.熟悉其他数据库的同学应该能很快明白的.Oracle | MongoDB | Mongoose |
---|---|---|
数据库实例(databaseinstance) | MongoDB实例 | Mongoose |
模式(schema) | 数据库(database) | mongoose |
表(table) | 集合(collection) | 模板(Schema)+模型(Model) |
行(row) | 文档(document) | 实例(instance) |
rowid | _id | _id |
Join | DBRef | DBRef |
Schema: 相当于一个数据库的模板.Model可以通过mongoose.model集成其基本属性内容.当然也可以选择不继承.
Model: 基本文档数据的父类,通过集成Schema定义的基本方法和属性得到相关的内容.
instance: 这就是实实在在的数据了.通过newModel()初始化得到.
他们各自间是怎样的关系呢?下图可以清晰的说明,以上3中实际上就是一个继承一个得到最后的数据.
我们先看一个demo吧:
'usestrict'; constmongoose=require('mongoose'); mongoose.connect('mongodb://localhost:27017/test'); constcon=mongoose.connection; con.on('error',console.error.bind(console,'连接数据库失败')); con.once('open',()=>{ //定义一个schema letSchema=mongoose.Schema({ category:String, name:String }); Schema.methods.eat=function(){ console.log("I'veeattenone"+this.name); } //继承一个schema letModel=mongoose.model("fruit",Schema); //生成一个document letapple=newModel({ category:'apple', name:'apple' }); //存放数据 apple.save((err,apple)=>{ if(err)returnconsole.log(err); apple.eat(); //查找数据 Model.find({name:'apple'},(err,data)=>{ console.log(data); }) }); })
到这里,实际上,mongoose我们已经就学会了.剩下就是看一看官方文档的API–CRUD相关操作.如果,大家觉得意犹未尽的话,可以继续看下面的深入浅出.而且,下面会附上实际应用中,mongoose的写法.
深入浅出mongoose
这里,我们根据上面的3个概念深入的展开一下.
Schema
这实际上是,mongoose中最重要的一个theroy.schema是用来定义documents的基本字段和集合的.在mongoose中,提供了Schema的类。我们可以通过实例化他,来实现创建Schema的效果.而不需要每次调用mongoose.Schema()这个丑陋的API.//frommongooseauthor varmongoose=require('mongoose'); varSchema=mongoose.Schema; varblogSchema=newSchema({ 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之所以能够定义documents,是因为他可以限制你输入的字段及其类型.mongoose支持的基本类型有:
String
Number
Date
Buffer
Boolean
Mixed
ObjectId
Array
其中,Mixed和ObjectId是mongoose中特有的,ObjectId实际上就是**_id**的一个映射.同样,mongoose里面有着和所有大众数据库一样的东西. 索引 –indexs
mongoose设置索引
这里设置索引分两种,一种设在Schemafiled,另外一种设在Schema.index里.
//在field设置 varanimalSchema=newSchema({ name:String, type:String, tags:{type:[String],index:true} }); //在Schema.index中设置. animalSchema.index({name:1,type:-1}); //1表示正序,-1表示逆序
实际上,两者效果是一样的.看每个人的喜好了.不过推荐直接在Schemalevel中设置,这样分开能够增加可读性.不过,官方给出了一个建议,因为在创建字段时,数据库会自动根据自动排序(ensureIndex).有可能严重拖慢查询或者创建速度,所以一般而言,我们需要将该option关闭.
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 newSchema({..},{autoIndex:false});//懒癌不推荐
另外,Schema另一大特色就是其methods.我们可以通过定义其methods,访问到实际上的所有内容.
定义Schema.methods
使用的方法很简单,就是使用 .methods即可.
//定义一个schema varfreshSchema=newSchema({name:String,type:String}); //添加一个fn. animalSchema.methods.findSimilarTypes=function(cb){ //这里的this指的是具体document上的this returnthis.model('Animal').find({type:this.type},cb); } //实际上,我们可以通过schema绑定上,数据库操作的所有方法. //该method实际上是绑定在实例的doc上的
定义完methods和property之后,就到了生成Model的阶段了.
实例Model
这里同样很简单,只需要 mongoose.model() 即可.
//生成,model类.实际上就相当于我们的一个collection varAnimal=mongoose.model('Animal',animalSchema); vardog=newAnimal({type:'dog'});
但是,这里有个问题.我们在Schema.methods.fn上定义的方法,只能在 newModel() 得到的实例中才能访问.那如果我们想,直接在Model上调用相关的查询或者删除呢?
绑定Model方法
同样很简单,使用 statics 即可.
//给model添加一个findByName方法 animalSchema.statics.findByName=function(name,cb){ //这里的this指的就是Model returnthis.find({name:newRegExp(name,'i')},cb); } varAnimal=mongoose.model('Animal',animalSchema); Animal.findByName('fido',function(err,animals){ console.log(animals); });
Mongoose还有一个superfeatrue--virtualproperty该属性是直接设置在Schema上的.但是,需要注意的是,VR并不会真正的存放在db中.他只是一个提取数据的方法.
//schema基本内容 varpersonSchema=newSchema({ name:{ first:String, last:String } }); //生成Model varPerson=mongoose.model('Person',personSchema); //现在我们有个需求,即,需要将first和last结合输出. //一种方法是,使用methods来实现 //schema添加方法 personSchema.methods.getName=function(){ returnthis.first+""+this.last; } //生成一个doc varbad=newPerson({ name:{first:'jimmy',last:'Gay'} }); //调用 bad.getName();
但是,像这样,仅仅这是为了获取一个属性,实际上完全可以使用虚拟属性来实现.
//schema添加虚拟属性 personSchema.virtual('fullName').get(function(){ returnthis.first+""+this.last; }) //调用 bad.fullName;//和上面的方法的结果是完全一致的
而且,经过测试,使用fn实现的返回,比VR要慢几十倍.一下是测试结果:
console.time(1); bad.getName(); console.timeEnd(1); console.time(2); bad.fullName; console.timeEnd(2); //结果为: 1:4.323ms;//method 2:0.253ms//VR
最后再补充一下,Schema中初始化的相关参数.
Schema参数 在 newSchema([options]) 中,我们需要设置一些相关的参数.
safe: 用来设置安全模式.实际上,就是定义入库时数据的写入限制.比如写入时限等.
//使用安全模式.表示在写入操作时,如果发生错误,也需要返回信息. varsafe=true; newSchema({..},{safe:safe}); //自定义安全模式.w为写入的大小范围.wtimeout设置写入时限.如果超出10s则返回error varsafe={w:"majority",wtimeout:10000}; newSchema({..},{safe:safe});
toObject: 用来表示在提取数据的时候,把documents内容转化为Object内容输出.一般而言只需要设置getters为true即可.
schema.set('toObject',{getters:true}); varM=mongoose.model('Person',schema); varm=newM({name:'MaxHeadroom'}); //实际打印出来的就是一个Object类型 console.log(m);//{_id:504e0cd7dd992d9be2f20b6f,name:'MaxHeadroomismyname'}
toJSON: 该是和toObject一样的使用.通常用来把documents转化为Object.但是,需要显示使用toJSON()方法,否则,不会起作用.实际上,没什么卵用…
看一下总结图谱:
看完schema之后,我们需要了解一下model的内容.
Model
实际上,Model才是操作数据库最直接的一块内容.我们所有的CRUD就是围绕着Model展开的.ok.还记得,我们是怎样创建一个model的吗?model的创建
model的创建实际上就是方法的copy.将schema上的方法,copy到model上.只是copy的位置不一样,一部分在prototype上,一部分在constructor中.
//frommongoosejs varschema=newmongoose.Schema({name:'string',size:'string'}); varTank=mongoose.model('Tank',schema);
这里,我们一定要搞清楚一个东西.实际上,mongoose.model里面定义的第一个参数,比如’Tank’,并不是数据库中的,collection.他只是collection的单数形式,实际上在db中的collection是’Tanks’.
ok,我们现在已经有了一个基本的Model.但并没有什么x用.接下来,正式到了drygoods(干货)时间.
model的子文档操作 这个就厉害了.本来mongodb是没有关系的.但是,mongoose提供了children字段.让我们能够轻松的在表间建立关系.现在,我们来创建一个子域:
varchildSchema=newSchema({name:'string'}); varparentSchema=newSchema({ children:[childSchema]//指明sub-doc的schema }); //在创建中指明doc varParent=mongoose.model('Parent',parentSchema); varparent=newParent({children:[{name:'Matt'},{name:'Sarah'}]}) parent.children[0].name='Matthew'; parent.save(callback);
现在,我们就已经创建了3个table.一个parent包含了两个child另外,如果我们想要查询指定的doc。则可以使用id()方法.
vardoc=parent.children.id(id);
子文档的CRUD,实际上就是数组的操作,比如push,unshift,remove,pop,shift等
parent.children.push({name:'Liesl'});
mongoose还给移除提供了另外一个方法–remove:
vardoc=parent.children.id(id).remove();
如果你忘记添加子文档的话,可以在外围添加,但是字段必须在Schema中指定
varnewdoc=parent.children.create({name:'Aaron'});
model的CRUD操作
model的创建 关于model的创建,有两种方法,一种是使用实例创建,另外一种是使用Model类创建.
varTank=mongoose.model('Tank',yourSchema); varsmall=newTank({size:'small'}); //使用实例创建 small.save(function(err){ if(err)returnhandleError(err); //saved! }) //使用Model类创建 Tank.create({size:'small'},function(err,small){ if(err)returnhandleError(err); //saved! })
上面已经完美的介绍创建的方法了.另外,官方给出一个提醒:由于mongoose,会自身连接数据库并断开.如果你手动连接,则创建model的方式需要改变.
//自己并没有打开连接: //注意,这里只是连接,并没有创建connection mongoose.connect('mongodb://localhost:27017/test'); //手动创建连接: varconnection=mongoose.createConnection('mongodb://localhost:27017/test'); varTank=connection.model('Tank',yourSchema);
然后,下面的API还是一样的.实际上,我们一般常用的写法为:
constmongoose=require('mongoose'); constSchema=mongoose.Schema; //设置连接位置 mongoose.connect('mongodb://localhost:27017/test'); varschema=newmongoose.Schema({name:'string',size:'string'}); varTank=mongoose.model('Tank',schema); varsmall=newTank({size:'small'}); //使用实例创建 small.save(function(err){ if(err)returnhandleError(err); console.log('创建成功'); })
这样,就不用自己去手动管连接的问题了.如果你,在后面想手动添加字段的话,可以使用.set方法.
//一个key/valye doc.set(path,value) //很多key/value doc.set({ path:value, path2:{ path:value } })
model的query model的查找主要提供了以下的API,给我们进行操作. find,findById,findOne,orwhere 在mongodb中,query返回的数据格式一般都是为JSON的.这点需要注意.
事实上,在mongoose中,query数据提供了两种方式.
callback: 使用回调函数,即,query会立即执行,然后返回到回调函数中.
Person.findOne({'name.last':'Ghost'},'nameoccupation',function(err,person){ if(err)returnhandleError(err); //getdata })
query: 使用查询方法,返回的对象.该对象是一个Promise,所以可以使用chain进行调用.最后必须使用exec(cb)传入回调进行处理.cb是一个套路,第一个参数永远是err.第二个就是返回的数据。
Person. find({ occupation:/host/, 'name.last':'Ghost', age:{$gt:17,$lt:66}, likes:{$in:['vaporizing','talking']} }). limit(10). sort({occupation:-1}). select({name:1,occupation:1}). exec(callback); //如果没有查询到,则返回[](空数组) //如果你使用findOne,没有的话则会返回null
童鞋,你觉得我会推荐哪种呢?
上面4个API,3个使用方式都是一样的,另外一个不同的是where.他一样是用来进行query.只是,写法和find系列略有不同.
where简介 where的API为: Model.where(path,[val]) path实际上就是字段,第二个参数.val表示可以用来指定,path=val的数据内容,你也可以不写,交给后面进行筛选.看一下对比demo吧:
User.find({age:{$gte:21,$lte:65}},callback); //等价于: User.where('age').gte(21).lte(65).exec(callback);
从上面的query中,我们可以看到有许多fn,比如gte,lte,$gte,$lte.这些是db提供给我们用来查询的快捷函数.我们可以参考,mongoose给的参考:
name | effect |
---|---|
select | 添加需要显示的字段,需要的字段在字段后加上:1,不需要的加上0;<br/>query.select({a:1,b:0});//显示a字段,隐藏b字段<br/>不能和distinct方法一起使用 |
distinct | 用来筛选不重复的值或者字段<br/>distinct(field).//筛选指定不重复字段的数据 |
$lt,$lte,$gt,$gte. | 分别对应:<,<=,>,>=.该字段是用在condition中的.如果,你想要链式调用,则需要使用<br/>lt,lte,ge,gte.<br/>eg:<br/>model.find({num:{$gt:12}},cb)<br/>model.where(‘num’).gt(12).exec(cb) |
$in | 查询包含键值的文档,<br/>model.find({name:{$in:[“jimmy”,“sam”]}})//相当于匹配jimmy或者sam |
$nin | 返回不匹配查询条件文档,都是指定数组类型<br/>model.find({name:{$nin:[“jimmy”,“sam”]}}) |
$ne | 表示不包含指定值<br/>model.find({name:{$ne:“sam”}}) |
$or | 表示或查询<br/>model.find({$or:[{color:‘red’},{status:‘emergency’}]}) |
$exits | 表示键值是否存在;<br/>model.find({name:{$exits:true}}) |
$all | 通常用来匹配数组里面的键值,匹配多个值(同时具有)<br/>$all:[“apple”,“banana”,“peach”]} |
$size | 用来查询数组的长度值<br/>model.find({name:{$size:3}});匹配name的数组长度为3 |
$slice | 用来获取数组字段的内容:<br/>query.slice(‘comments’,5) |
**limit:**用来获取限定长度的内容.
query.limit(20);//只返回前20个内容
skip: 返回,跳过指定doc后的值.
query.skip(2);
sort: 用来设置根据指定字段排序.可以设置为1:升序,-1:降序.
query.sort({name:1,age:-1});
实际上,关于query,我们需要了解的也就差不多了.
我们接下来,来看一下remove. mongooseremove操作
官方提供的API,就是remove.同样,移除的效果,我们可以使用两种方式实现。一是回调函数,二是,链式调用.
Model.find().remove({name:'AnneMurray'}).remove(fn); //或者直接添加回调 Model.find().remove({name:'AnneMurray'},cb)
另外,我们可以直接在Model上调用.因为remove也是Schema定义的statics方法.而且,remove返回一个Promise对象
product.remove().then(function(product){ ... }); //或者直接传入回调 Tank.remove({size:'large'},function(err){ if(err)returnhandleError(err); //removed! });
最后,我们再看一下update.然后mongoose就基本结束了 update操作: 这里,我只说一下API就好.因为update比起上面来说,还是比较简单的. Model.update(conditions,doc,[options],[callback])
conditions: 就是query.通过query获取到指定doc
doc: 就是用来替换doc内容的值.
options: 这块需要说一下.
safe(boolean)是否开启安全模式(defaultfortrue)
upsert(boolean)如果没有匹配到内容,是否自动创建(defaultforfalse)
multi(boolean)如果有多个doc,匹配到,是否一起更改(defaultforfalse)
strict(boolean)使用严格模式(defaultforfalse)
overwrite(boolean)匹配到指定doc,是否覆盖(defaultforfalse)
runValidators(boolean):表示是否用来启用验证.实际上,你首先需要写一个验证.关于如果书写,验证大家可以参考下文,validate篇(defaultforfalse)
Model.update({age:18},{$set:{name:'jasonborne'}},{multi:true},function(err,raw){ if(err)returnhandleError(err); console.log('raw就是mongodb返回的更改状态的falg',raw); //比如:{ok:1,nModified:2,n:2} });
其中的$set是,用来指明更新的字段.另外,mongoose还提供了一个:findByIdAndUpdate(id,doc[,options][,callback]);方法.关于mongoose的更新helper函数.童鞋们可以参考一下.
validation
说完了,mongoose的body之后.我们接着来看一下,官方给mongoose穿上的漂亮的衣服.其中一件,比较吸引人的是–validation.在你save数据之前,你可以对数据进行一些列的validation.来防止某天你傻不拉几的把数据完整性给破坏了.mongoose贴心的提供了几个built-in的验证函数.required: 表示必填字段.
newSchema({ name:{ type:String, required:[true,"name是必须的"]//第二个参数是错误提示信息 } })
min,max: 用来给Number类型的数据设置限制.
varbreakfastSchema=newSchema({
eggs:{
type:Number,
min:[6,'Toofeweggs'],
max:12
}
});
enum,match,maxlength,minlength: 这些验证是给string类型的.enum就是枚举,表示该属性值,只能出席那那些.match是用来匹配正则表达式的.maxlength&minlength显示字符串的长度.
newSchema({
drink:{
type:String,
enum:['Coffee','Tea']
},
food:{
type:String,
match:/^a/,
maxlength:12,
minlength:6
}
})
mongoose提供的helperfn就是这几种,如果你想定制化验证.可以使用customvalidation.
newSchema({
phone:{
type:String,
validate:{
validator:function(data){
return/\d{3}-\d{3}-\d{4}/.test(data);
},
message:'{VALUE}isnotavalidphonenumber!'//VALUE代表phone存放的值
},
required:[true,'Userphonenumberrequired']
}
})
另外,还可以额外添加验证.
vartoySchema=newSchema({
color:String,
name:String
});
varvalidator=function(value){
return/blue|green|white|red|orange|periwinkle/i.test(value);
};
toySchema.path('color').validate(validator,
'Color`{VALUE}`notvalid','Invalidcolor');
现在,我们已经设置了validation.但是你不启用,一样没有什么卵用.实际上,我们也可以把validation当做一个中间件使用.mongoose提供了两种调用方式.一种是内置调用,当你使用.save方法时,他会首先执行一次存储方法.
cat.save(function(error){
//自动执行,validation
});
另外一种是,手动验证–指定validate方法.
//上面已经设置好user的字段内容.
user.validate(function(error){
//error就是验证不通过返回的错误信息
assert.equal(error.errors['phone'].message,
'555.0123isnotavalidphonenumber!');
});
});
事实上,在validate时,错误的返回信息有以下4个字段:kind,path,value,andmessage;
kind: 用来表示验证设置的第二个参数.一般不用
phone:{
type:String,
validate:{
validator:function(data){
return/\d{3}-\d{3}-\d{4}/.test(data);
},
message:'{VALUE}isnotavalidphonenumber!',//VALUE代表phone存放的值
kind:"invalidphone"
}
})
path: 就是字段名
value: 你设置的错误内容
message: 提示错误信息看一个整体demo吧:
varvalidator=function(value){
return/blue|green|white|red|orange|periwinkle/i.test(value);
};
Toy.schema.path('color').validate(validator,
'Color`{VALUE}`notvalid','Invalidcolor');//设置了message&&kind
vartoy=newToy({color:'grease'});
toy.save(function(err){
//errisourValidationErrorobject
//err.errors.colorisaValidatorErrorobject
assert.equal(err.errors.color.message,'Color`grease`notvalid');//返回message
assert.equal(err.errors.color.kind,'Invalidcolor');
assert.equal(err.errors.color.path,'color');
assert.equal(err.errors.color.value,'grease');
assert.equal(err.name,'ValidationError');
//访问color也可以直接上errors["color"]进行访问.
});
在Model.update那一节有个参数–runValidators.还没有详细说.这里,展开一下.实际上,validate一般只会应用在save上,如果你想在update使用的话,需要额外的trick,而runValidators就是这个trick.
varopts={runValidators:true};
Test.update({},update,opts,function(error){//额外开启runValidators的验证
//Therewillneverbeavalidationerrorhere
});
我们来看一下基本总结吧:
population
originally,mongodb本来就是一门非关系型数据库。但有时候,我们又需要联合其他的table进行数据查找。这时候,一般的做法就是实现两次查询,效率我就呵呵了.此时,mongoose说了一句:麻麻,我已经都把脏活帮你做好了.感动~有木有~这就是mongoose提供的population.用来连接多表数据查询.一般而言,我们只要提供某一个collection的_id,就可以实现完美的联合查询.population用到的关键字是: ref用来指明外联的数据库的名字.
一般,我们需要在schema中就定义好.
varmongoose=require('mongoose')
,Schema=mongoose.Schema
varpersonSchema=Schema({
_id:Number,
name:String,
age:Number,
stories:[{type:Schema.Types.ObjectId,ref:'Story'}]
});
varstorySchema=Schema({
_creator:{type:Schema.Types.ObjectId,ref:'Person'},
title:String
});
这里就指明了,外联数据表的应用关系personSchema<stories>By_id=>StorystorySchema<_creator>By_id=>Person实际上,就是通过_id的相互索引即可.这里需要说明的是,_id应该是某个具体model的id.
我们来看一下,接下来应该如何利用population实现外联查询.
constsam=newPerson({
name:'sam',
_id:1,
age:18,
stories:[]
});
sam.save((err,sam)=>{
if(err)returnerr;
letstory=newStory({
_creator:sam._id,
title:"喜剧之王"
})
})
Story.findOne({title:"喜剧之王"}).populate('_creator').exec((err,story)=>{
if(err)console.log(err);
console.log(story._creator.name);
})
//使用populate来指定,外联查询的字段,而且该值必须是_id才行
现在es6时代的来临,generator,async/await盛行.也带来另外一种书写方式–middleware.在mongoose也有这个hook,给我们使用.(说实话,有点像AOP)
mongoose&&middleware
mongoose里的中间件,有两个,一个是pre,一个是post.pre: 在指定方法执行之前绑定。中间件的状态分为parallel和series.
post: 相当于事件监听的绑定
这里需要说明一下,中间件一般仅仅只能限于在几个方法中使用.(但感觉就已经是全部了)
doc方法上:init,validate,save,remove;
model方法上:count,find,findOne,findOneAndRemove,findOneAndUpdate,update
pre
我们来看一下,pre中间件是如何绑定的.//series执行,串行
varschema=newSchema(..);
schema.pre('save',function(next){
//exesomeoperations
this.model.
next();//这里的next()相当于间执行权给下一个pre
});
在你调用model.save方法时,他会自动执行pre.如果你想并行执行中间件,可以设置为:
schema.pre('save',true,function(next,done){
//并行执行下一个中间件
next();
});
post
相当于绑定啦~post会在指定事件后触发schema.post('save',function(doc){
//在save完成后触发.
console.log('%shasbeensaved',doc._id);
});
当save方法调用时,便会触发post绑定的save事件.如果你绑定了多个post。则需要指定一下中间件顺序.
schema.post('save',function(doc,next){
setTimeout(function(){
console.log('post1');
next();
},10);
});
schema.post('save',function(doc,next){
console.log('post2');
next();
});
实际上,post触发的时间为:
varschema=newSchema(..);
schema.post('save',function(doc){
console.log('thisfiredafteradocumentwassaved');
});
varModel=mongoose.model('Model',schema);
varm=newModel(..);
m.save(function(err){
console.log('thisfiresafterthe`post`hook');
});
另外,在post和find中,是不能直接修改doc上的属性的.即,像下面一样的,没有效果
articleSchema.post('find',function(docs){
docs[1].date=1
})
docs[1].date的值还是不变
相关文章推荐
- 【深入浅出jQuery】源码浅析--整体架构【转载】
- 【转载】nodejs+express+ejs+mongoose实例
- 转载 - Android深入浅出Binder机制
- 【转载】ASP.NET之旅--深入浅出解读IIS架构
- [转载] Mongoose - 让NodeJS更容易操作Mongodb数据库
- 深入浅出理解闭包(转载)
- 深入浅出-iOS程序性能优化 (转载)
- [转载]替换运行中的文件(深入浅出)
- 深入浅出SQL之左连接、右连接和全连接 (转载)
- 深入浅出net泛型编程[转载]
- 深入浅出spring IOC中三种依赖注入方式(转载自:龙腾四海365)
- MONGOOSE – 让NODE.JS高效操作MONGODB(转载)
- 【转载】深入浅出URL编码
- [转载]深入浅出UML类图
- 深入浅出JSON(转载)
- [转载]深入浅出Visual C++动态链接库(Dll)编程
- 深入浅出:进程、线程、协程、同步、异步、回调(转载)
- 【转载】深入浅出数据库索引原理
- mongoose如何取得全部结果数量并只提取部分结果 - 转载,待试验
- 对TCP/IP网络协议的深入浅出归纳(转载)