// 1,引入mongoose
const mongoose = require('mongoose')
// 2. 连接本地数据库
let db = mongoose.connect('mongodb://localhost/test')
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
});
mongoose里,一切始于Schema:
let tomSchema = mongoose.Schema({
name:String
})
//接着,把这个Schema编译成一个Model
let Tom = mongoose.model('Tom',tomSchema)
// 给这个model加一个code方法
Tom.methods.code = function(){
let nickname = this.name ? "The programmar name is :" + this.name:'I don't have name'
console.log(nickname)
}
//model是我们构造document的class,每个document都是一个Tom对象
let Tomliu = new Tom({name:'liugezhou'})
Tomliu.code() //The programmar name is :liugezhou
// save
Tomliu.save(function(err,item){
if (err) return console.error(err);
item.speak();
})
// 获取所有的Tom
Tom.find(function(err,tomlius){
if(err) return console.error(err);
console.log(tomlius)
})
//获取特定数据
Tom.find({name:/^liugezhou/},callback)
语法:
允许使用的Schematypes有:
除了映射collection外,还可以定义
model
我们要把一个Schema转化为一个model,要使用
collection和document
实例方法methods
const animalSchema = mongoose.Schema({type:String,name:String})
animalSchema.methods.findSameType = function (cb){
return this.model('Animal').find(type:this.type,cb)
}
const Animal = mongoose.model('Animal',animalSchema)
const dog = new Animal({type:'dog'})
dog.findSameType(function(err,dogs){
console.log(dogs)
})
静态方法
animalSchema.statics.findByName = function(name,cb) {
return this.find({name:new RegExp(name,'i')},cb)
}
const Animal = mongoose.model('Animal',animalSchema)
Animal.findByName('fido',function(err,animal){
console.log(animals)
})
查询助手
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);
});
索引
var animalSchema = new Schema({
name: String,
type: String,
tags: { type: [String], index: true } // field level
});
animalSchema.index({ name: 1, type: -1 }); // schema level
虚拟值 Virtual
// 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 axl = new Person({
name: { first: 'Axl', last: 'Rose' }
});
console.log(axl.name.first + ' ' + axl.name.last); // Axl Rose
personSchema.virtual('fullName').get(function () {
return this.name.first + ' ' + this.name.last;
});
console.log(axl.fullName); // Axl Rose
你也可以设定虚拟值的 setter ,下例中,当你赋值到虚拟值时,它可以自动拆分到其他属性:
personSchema.virtual('fullName').
get(function() { return this.name.first + ' ' + this.name.last; }).
set(function(v) {
this.name.first = v.substr(0, v.indexOf(' '));
this.name.last = v.substr(v.indexOf(' ') + 1);
});
axl.fullName = 'William Rose'; // Now `axl.name.first` is "William"
选项
new Schema({..}, options);
// or
var schema = new Schema({..});
schema.set(option, value);
以下是mongoose的所有合法SchemaTypes:
SchemeType选项
var schema1 = new Schema({
test: String // `test` is a path of type String
});
var schema2 = new Schema({
test: { type: String } // `test` is a path of type string
});
var shema2 = new Schema({
test:{
type:String,
lowercase:true
}
})
全部可用
索引相关
可以使用 schema type定义索引相关
操作缓存
就是说不必等待上面的connect连接成功后,就可以使用创建的 Mongoose models 禁用缓存,要修改 bufferCommands配置,mongoose.set(‘bufferCommands’,fasle)
选项
connect 方法也接受 options 参数,这些参数会传入底层 MongoDB 驱动。
回调
connect()函数接受回调函数,或返回一个Promise
keepAlive
对于长期运行的后台应用,启用毫秒级 keepAlive 是一个精明的操作。不这么做你可能会经常 收到看似毫无原因的 “connection closed” 错误。 mongoose.connect(uri,{keepAlive:120})
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
上面的参数 Tank是跟model对应的集合(collection)对应的单数形式。 Mongoose会自动找到名称是model的名字的复数形式。 比如上例,Tank这个model对应数据库中tanks这个collection .model()这个函数是对 schema做了拷贝 确保在调用.model()之前把所有需要的东西都加进shema里。
构造documents
const Tank = mongoose.model('Tank',TankSchema)
const small = new Tank({ size:' small'})
small.save(function(err){
if (err) return hanldeError(err)
})
// or
Tank.create({size:'small'},function(err,small){
if (err) return handleError(err)
})
查询
删除
Tank.remove({size:small},function(err){
if(err) return handler(err)
})
更新
model
的 update
方法可以修改数据库中的文档,不过不会把文档返回给应用层。更新 使用findById:
Tank.findById(id,function(err,tank){
if (err) return handlerError(err)
tank.size = 'large';
//tank.set({size:'large'})
tank.save(function(err,updateTank){
if (err) return handlerError(err)
res.send(updateTank)
})
})
Tank.update({_id:id},{$set:{size:‘large’}},callback)
Tank.findByIdAndUpdate(id,{$set:{size:'large'}},{new:true},function(err,tank){
if (err) return handlerError(err)
res.send(tank)
})
子文档是指嵌套在另一个文档中的文档。 在Mongoose中,意味着你可以在里嵌套另一个schema。 Mongoose子文档有两种不同的概念:子文档数组和单个嵌套子文档
const chidlSchema = new Schema({name:String})
const parentSchema = new Schema({
children:[childSchema],
child:childSchema
})
子文档与文档的区别是 子文档不能单独保存,他们会在他们的顶级文档保存时保存。
const Parent = mongoose.model('Parent',parentSchema)
const parent = new Parent({children:[{name:'liu'},{name:'ge'},{name:'zhou;}]})
parent.children[0].name = 'liu'
parent.save(callback)
我们看一下demo,查询persons表中name中属性last为Ghost值的文档,只查询 name和occupation两个字段
const Person = mpngoose.model('Pseron',PersonSchema);
Person.findOne({name.last:'Ghost'},'name occupation',function(err,person){
if(err) return handleError(err)
console.log('%s %s is a %s',person.name.fisrt,person.name.last,person.occupation)
})
查询结果的格式取决于做什么操作:
pre
pre钩子分为『串行』和『并行』两种
串行中间件一个接一个的执行。具体来说,上一个中间件调用 next 的时候下一个执行
const schema = new Schema(..);
schema.pre('save',function(next){
// to stuff
next()
})
在 mongoose5.x 中,除了手动调用 next 函数,还可以返回一个 Promise,甚至是 async/await。
schema.pre('save',function(){
return doStuff().
then(()=> doMoreStuff())
})
// or
shcema.pre('save',async function(){
await doStuff();
await doMoreStuff();
})
并行中间件提供细粒度流控制。
const schema = new Schema(..)
shcema.pre('save',true,function(next,done){
next()
setTimeout(done,100)
})
在这个例子中,save 方法将在所有中间件都调用了 done 方法的时候才会执行。 使用场景:
Post
Post中间件在方法执行之后调用,这个时候每个 pre 中间件都已完成
schema.post('init',function(doc){
console.log('%s has been initialized from the db', doc._id);
})
schema.post('validate',function(doc){
console.log('%s has been validated (but not saved yet)', doc._id);
})
schema.post('save',function(doc){
console.log('%s has been saved', doc._id);
})
schema.post('remove',function(doc){
console.log('%s has been removed', doc._id);
})
如果你给 post 钩子的回调函数传入两个参数,mongoose 会认为第二个参数是 next()函数,可以通过 next 触发下一个中间件
schema.post('save',function(doc,next){
setTimeout(function(){
console.log('pot1')
next()
},100)
})
schema.post('save', function(doc, next) {
console.log('post2');
next();
});
save()函数触发 validate()钩子,mongoose validate()钩子其实就是 pre(‘save’)钩子,这意味着所有pre(‘validate’)和 post(‘validate’)钩子都会在 pre(‘save’)之前调用。
pre 和 post save()钩子都不执行于 update()、 findOneAndUpdate()等情况 mongoose4.x为这些函数制定了新钩子
schema.pre('find',function(){
conosle.log(this instanceof mongoose.query) //true
this.start = Date.now()
})
schema.post('find',function(result){
conosle.log(this instanceof mongoose.query) //true
// prints returned documents
console.log('find() returned ' + JSON.stringify(result));
// prints number of milliseconds the query took
console.log('find() took ' + (Date.now() - this.start) + ' millis');
})
错误处理中间件
next()
执行错误时,中间件执行立即停止。但是我们有特殊的 post 中间件技巧处理这个问题 —— 错误处理中渐渐,它可以在出错后执行你指定的代码。 错误处理中间件比普通中间件多一个error
参数,并且err
作为第一个参数传入。 而后错误处理中间件可以让你自由地做错误的后续处理
const schema = new Schema({
name:{
type:String,
unique:true
}
})
schema.post('save',function(err,doc,next){
if (error.name === 'MongoError' && error.code === 11000) {
next(new Error('There was a duplicate key error'));
} else {
next(error);
}
})
Person.create([{name:'liu'},{name:'Gezhou'}]);
demo MongoDb 在 3.2之后,也有像 sql 中的 join 聚合操作,那就死$lookup,而 mongoose 拥有更强大的 populate,可以让你在别的 collection 中引用 document。 Populate 可以自动替换 document 中的指定字段,替换内容从其他 collection 获取,我们填充(populate)单个或者多个 document、单个或者多个对象,甚至是 query 返回的一切对象:
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const personSchema = Schema({
_id:Schema.types.ObjectId,
name:String,
age:Number,
stories:[{type:Schema.types.ObjectId,ref:'Story'}]
})
const storySchema = Schema({
author:{type:Schema.types.ObjectId,ref:'Person'},
title:String,
fans:[{type:Schema.types.ObjectId,ref:'Person'}]
})
const Story = mongose.model('Story',storySchema)
const Person = mongose.model('Person',personSchema)
我们创建了两个model,Person model中的 stories 字段为 ObjectID 数组,ref 选项告诉mongoose 在填充的时候使用哪个 model,上面的例子就是指 Story 的 model。所有储存在此的_id 都必须是 Story model 中的 document 的 _id
保存 refs 保存 refs 与保存普通属性一样,把_id的值赋给他就好了
const author = new Person({
_id:new mongoose.Types.objectId(),
name:'liugezhou',
age:18
})
author.save(function(err){
if (err) return handleError(err);
const story1 = new Story({
title:'my book',
author:author._id
})
story1.save(function(err){
if (err) return handleError(err);
})
})
Population
Story.
findOne({title:'my book'}).
populate('author').
exec(function(err,story){
if (err) return handleError(err);
console.log('The author is %s', story.author.name);
})
设置被填充字段 mongoose4.0之后,你可以手动填写一个字段
Story.findOne({title:'my book'},function(err,story){
if (err) return handleError(err);
story.author = author
console.log(story.author.name);
})
Discriminator是一种 schema 继承机制。它允许你在相同的底层MongoDb collection上使用部分重叠的 schema 建立多个 model。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有