您的位置:首页 > 数据库 > Mongodb

Node.js 模块之【mongoose】MongoDB操作模块

2017-03-16 20:27 981 查看

1. 安装mongoose

npm i mongoose --save-dev


2. 引入mongoose

const mongoose = require('mongoose');


3. 连接数据库

mongoose.Promise = global.Promise;
mongoose.connect(DBConfig.DBUrl);


4. mongoose支持的数据类型

- String
- Number
- Date
- Buffer
- Boolean
- Mixed
- ObjectId
- Array


5. 定义Schema方式

构造器方式

var userSchema = new Schema({
username: 'string'
});


追加方式

var userSchema = new Schema;
userSchema.add({username: 'string'});


6. 定义Schema的实例方法

// 定一个用户Schema
var userSchema  = new Schema({username: 'string'});

// 为用户Schema添加一个detial实例方法
userSchema.methods.detial = function(callback){
return this.model('user').find({}, callback);
}
// 将用户Schema编译为用户模型
var UserModel =  mongoose.model('user', userSchema);

// 通过模型构造器,创建一个用户对象
var user = new UserModel({username:'zhagener', password:'123'});

// 调用用户对象的detail实例方法
user.detial(function(err,docs){
console.log(docs);
});


7. 定义Schema的静态方法

// 定一个用户Schema
var userSchema  = new Schema({username: 'string'});

// 为用户Schema添加一个findByName静态方法
userSchema.statics.findByName = function(username, callback){
return this.find({ username: username }, callback);
}

// 将用户Schema编译为用户模型
var UserModel =  mongoose.model('user', userSchema);

// // 调用用户模型的findByName静态方法
UserModel.findByName('zhagener', function(err, users) {
console.log(users);
});


8. 为Schema定义查询助手

// 定义用户Schema
var userSchema = new Schema({username: 'string'});

// 定义用户Schema的查询助手
userSchema.query.byName = function(username){
return this.find({username: username});
};

// 使用查询助手
var UserModel = mongoose.model('user', userSchema);

UserModel.find().byName('zhagener').exec(function(err,users){
console.log(docs);
});


9. 为Schema定义虚函数

Virtuals are document properties that you can get and set but that do not get persisted to MongoDB. The >getters are useful for formatting or combining fields, while setters are useful for de-composing a single value >into multiple values for storage.

文档属性中的虚函数能够设置或获取,但是不会持久化到MongoDB中,其中getter对于格式化或者合并字段是非常适用,setter用于将单个值解析多个值进行存储非常适用。

// 创建用户Schema
var userSchema = new Schema({
name:{
firstName: 'string',
lastName: 'string'
}
});

// 为用户Schema添加全名虚函数(getter)
userSchema.virtual('fullName').get(function(){
return this.name.firstName + ' ' + this.name.lastName;
});

// 为用户Schema添加全名虚函数(setter)
userSchema.virtual('fullName').set(function(fullName){
var names = fullName.split(/\s+/);
this.name.firstName = names[0];
this.name.lastName = names[1];
});

// 将用户Schema编译为用户模型
var UserModel = mongoose.model('user', userSchema);

// 创建一个用户实例
var user = new UserModel({name:{firstName:'zhagener', lastName:'qier'}});

// 调用用户实例的虚函数fullName(getter)
console.log(user.fullName);

// 调用用户实例的虚函数fullName(setter)
user.fullName = 'a b';

// 调用用户实例的虚函数fullName(getter)
console.log(user.fullName);


10. Schema选项

10.1 Schema选项设置方法

构造器方式(集中配置)

new Schema({..}, options);// options : json object


追加方式(单个追加)

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


10.2 Schema选项列表

- autoIndex
- capped
- collection
- emitIndexErrors
- id
- _id
- minimize
- read
- safe
- shardKey
- strict
- toJSON
- toObject
- typeKey
- validateBeforeSave
- versionKey
- skipVersioning
- timestamps
- retainKeyOrder


[b]10.2.1 Schema选项:autoIndex[/b]

创建不创建索引的Schema

// 禁止自动创建索引
var userSchema = new Schema({..}, { autoIndex: false });
var UserModel = mongoose.model('user',userSchema);
UserModel.ensureIndexes(callback);


[b]10.2.2 Schema选项:timestamp[/b]

创建默认存在{updatedAt 、created_at}字段的Schema

var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing();
thing.save(); // `created_at` & `updatedAt` will be included


11. Schema 类型:string (详细)

11.1 string 枚举值限定

自定义错误消息


// 定义性别枚举类型
var sexs = {
values: ['male', 'female'],
message: 'sexs not exist : `{PATH}` the value `{VALUE}`'
}

// 创建用户Schema
var userSchema = new Schema({ sex: { type: String, enum: sexs }});

// 将用户Schema编译为用户模型
var UserModel = mongoose.model('user', userSchema);

// 创建用户实例(zhagener),并赋值一个非法的性别类型 `帅哥`
var zhagener = new UserModel({ sex: 'Handsome guy' });

// 保存用户实例(zhagener)
zhagener.save(function (err) {
console.error(String(err))
zhagener.sex = 'male' // 报错后重置性别为合法的男性
zhagener.save(function(err) {
console.log(err);
}) // success
});


11.2 string value大/小写化

存储时,将所有字符转换为大/小写


var userSchema = new Schema({email:{type: String, lowercase: true}}); // 大写:uppercase
var UserModel = mongoose.model('user',userSchema);
var zhagener = new UserModel({email:'ZhageneR@163.com'});
zhagener.save();// email:zhagener@163.com


11.3 string 正则约定化

存储时,对value进行正则验证


var matchRex = [/^China/,"your contry is not china : {VALUE}"];
var userSchema = new Schema({contry:{type:String, match:matchRex}});
var UserModel = mongoose.model('user',userSchema);
var zhagener = new UserModel({contry:'Bangzi'});
zhagener.validate(function(err) {
console.log(err);// ValidatorError: your contry is not china : bangzi
});


11.3 string 最大/小长度限定

存储时,对value进行最大长度限定


var maxlength = [11, "your phone number length is invalid (11) : {VALUE}"];
var userSchema = new Schema({phoneNo:{type:String, maxlength:maxlength}}); // 最小长度:minlength
var UserModel = mongoose.model('user',userSchema);
var zhagener = new UserModel({phoneNo:135147599999});
zhagener.save(function(err) {
console.log(err);// ValidatorError: your phone number length is invalid (11) : 135147599999
zhagener.phoneNo = 13514759999;
zhagener.save();
});


11.4 string 修剪

存储时,对value进行去前后空格


var userSchema = new Schema({username:{type: String, trim: true}});
var UserModel = mongoose.model('user',userSchema);
var zhagener = new UserModel({username: ' hhahaha      '}); //    "username" : "hhahaha",
zhagener.save(function(err) {
if (err) {
console.log(err)
}
});


12. Schema 类型:Number(详细)

12.1 number 最大/小值限定

自定义错误消息


var max = [150, "you are Tortoise ? (age < 150): {VALUE}"]
var userSchema = new Schema({age:{type: Number, max:max}});// 最小值:min
var UserModel = mongoose.model('user',userSchema);
var zhagener = new UserModel({age: 200});
zhagener.validate(function(err) {
console.log(err);// ValidatorError: you are Tortoise ? (age < 150): 200
});


13. Schema 类型:Date(详细)

13.1 Date 最大/小值限定

自定义错误消息


var max = [Date('2014-10-01'), "max time Date('2014-10-01'): {VALUE}"] //最小值:min
var userSchema = new Schema({
createdAt: {
type: Date,
max: max
}
});
var UserModel = mongoose.model('user', userSchema);
var zhagener = new UserModel({
createdAt:Date.now()
});
zhagener.validate(function(err) {
console.log(err); // ValidatorError: max time Date('2014-10-01'): Thu Mar 16 2017 19:09:26 GMT+0800 (中国标准时间)
});


14. Model(模型)(详细)

14.1 通过模型创建实例方式

构造器方式(需要调用实例的save保存至数据库)

var userSchema = new Schema({
username: 'string',
password: 'string'
});
UserModel =  mongoose.model('user', userSchema);
var zhagener = new UserModel({username: 'zhagener'});


调用create方法方式(直接保存至数据库)

UserModel.create({username: 'zhagener'},function(err,zhagener) {
if (err) {}
// zhagener has save to mongoDB
});


14.2 通过模型查询数据

UserModel.find().where('username').eq('zhagener').exec(function(err,docs) {
console.log(docs);// [ { _id:58ca7a0f922f59379cae3778, username:'zhagener', __v: 0 } ]
});


14.3 通过模型删除数据

UserModel.create({username: 'zhagener'},function(err,zhagener) {
if (err) {}
// zhagener has save to mongoDB
UserModel.remove({username:'zhagener'},function(err) {
if(err)
console.log(err);
})
UserModel.find().where('username').eq('zhagener').exec(function(err,docs) {
console.log(docs);// [{_id:58ca7a0f922f59379cae3778, username:'zhagener', __v:0 } ]
});
});


15. Document(文档)(详细)

15.1 更新数据的两种方式

UserModel.create({username: 'zhagener'},function(err,zhagener) {
UserModel.find().where('username').eq('zhagener').exec(function(err,docs) {
console.log(docs);
UserModel.findByIdAndUpdate(docs[0]._id,
{
$set: { username: 'zhagener2' }
},
{ new: true },
function (err, zhagener2) {
if (err) return handleError(err);
console.log(zhagener2);
});
});

});


UserModel.create({username: 'zhagener'},function(err,zhagener) {
if (err) {}
// zhagener has save to mongoDB
// UserModel.remove({username:'zhagener'},function(err) {
//  if(err)
//      console.log(err);
// })
UserModel.find().where('username').eq('zhagener').exec(function(err,docs) {
console.log(docs);// [ { _id: 58ca7a0f922f59379cae3778, username: 'zhagener', __v: 0 } ]
UserModel.update({username:'zhagener'},{$set:{username:'haha'}},function(err,docs) {
if (err) {}
console.log(docs)// haha
})
});

});


16. 子文档

16.1 定义子文档

Sub-documents enjoy all the same features as normal documents. The only difference is that they are not saved individually, they are saved whenever their top-level parent document is saved.

子文档拥有一个正常文档的所有特性,唯一的不同是不能够独立的存储,只有在父级文档保存时子文档同时也被存储。

var UserSchema = new Schema({
username: {
type: String
},
password: {
type: String
},
githubId: {
type: String
},
blogs:[BlogSchema] // 指定字表Schema
});
// 将用户Schema编译为用户模型
var UserModel = mongoose.model('User', UserSchema);
// 创建用户实例zhagener
var zhagener = new UserModel({
username: 'zhagener',
blogs: [{
title: 'first',
content: 'first content'
}, {
title: 'second',
content: 'second content'
}]
});
zhagener.save();




16.2 子文档错误冒泡

If an error occurs in a sub-document’s middleware, it is bubbled up to the save() callback of the parent, so error handling is a snap!

如果子文档操作的中间件中发生异常,异常将会冒泡至父级保存的回调中。

var BlogSchema = new Schema({
title:{type: String},
content:{type: String}
});

BlogSchema.pre('save',function(next) {
if(this.title == 'first'){
return next(new Error('title can not defined as first'));
}
});

var UserSchema = new Schema({
username: {
type: String
}, //用户账号
password: {
type: String
},
githubId: {
type: String
},
blogs:[BlogSchema]
});

var UserModel = mongoose.model('User', UserSchema);

var zhagener = new UserModel({
username: 'zhagener',
blogs: [{
title: 'first',
content: 'first content'
}, {
title: 'second',
content: 'second content'
}]
});

zhagener.save(function(err,docs) {
if(err){
console.log(err);// title can not defined as first
}
});


16.3. 查询一个子文档

Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.

每个文档都有一个_id字段,文档数组有一个id方法,通过此方法传入子文档的_id字段就可查到子文档

async.waterfall([
// 保存用户实例,并添加上两个博客
function(callback) {
var zhagener = new UserModel({
username: 'zhagener',
blogs: [{
title: 'first blog',
content: 'first content'
}, {
title: 'first blog',
content: 'first content'
}]
});
zhagener.save();
callback(null,zhagener)
},
// 获取实例对象
function(newUser,callback) {
UserModel.find({username:newUser.username}).exec(function(err, docs) {
var zhagener = docs[0];
callback(null,zhagener);
})
},
// 根据实例对象查找对应的第一篇博客内容
function(owner,callback) {
try{
var blog = owner.blogs.id(owner.blogs[0]._id);
console.log("+++blog:"+blog);
callback(null, blog);

}catch(error){
callback(error);
}
}

],function(err,results) {
console.log("Results: "+results);
});


16.4. 操作子文档(push)

MongooseArray methods such as push, unshift, addToSet, and others cast arguments to their proper types transparently:

mongoose中的数组的方法(push、unshift、addToSet….)及参数,都类同原生JS

var anonymous = new UserModel;
anonymous.blogs.push({
title: 'first blog',
content: 'first content'
}, {
title: 'second blog',
content: 'second content'
});
var firstBlog = anonymous.blogs[0];
console.log("isNew:___ "+firstBlog.isNew); // isNew:___ true
anonymous.save(function(err) {
if (err) {
console.log(err);
}
console.log(anonymous);
})


16.5. 操作子文档(create)

Sub-docs may also be created without adding them to the array by using the create method of MongooseArrays.

子文档也可通过Mongoose数组的create方法进行创建,但是创建的文档不会添加到父级文档中

var newdoc = anonymous.blogs.create({ title: 'first', content: 'first content' });
console.log(anonymous); // blogs:[]


16.5. 操作子文档(remove)

async.waterfall([
// 查找zhagener对象(用于两篇博客)
function(callback) {
UserModel.findOne({username:'zhagener'},function(err,doc) {
if (err) {
callback(err);
}
callback(null,doc);
})
},
// 删除zhagener对象的第一篇博客
function(zhagener,callback) {
zhagener.blogs.id(zhagener.blogs[0]._id).remove();
callback(null,zhagener);
},
// 保存zhagener对象
function(zhagener,callback) {
zhagener.save();
callback(null,zhagener);
}

],function(err,results) {
if (err) {
console.log(err);
}
console.log(results);
});


16.6 另外一种声明字表语法

If you don’t need access to the sub-document schema instance, you may also declare sub-docs by simply passing an object literal:

如果你不需要访问子文档的实例是,你还可以通过一个对象声明字表

注:可能对于字表的操作性变得不那么灵活,比如虚函数就不能够使用,次场景只使用[特别….特别]简单的子文档时使用。

var userSchema = new Schema({
blogs: [{ title: 'string' , content: 'string'}]
})


16.7 父级文档嵌入单个子文档

var githubSchema = new Schema({ name: 'string', githubId: 'string' });

var UserSchema = new Schema({
githubCount: githubSchema
});


17. mongoose中的文档查询

mongoose中的查询提供了两种方式:

JSON doc方式

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);


Query builder方式

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);


18. 流数据查询

待完成

19. 多表关联

There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.

在MongoDB中没有多表关联的,但是我们可以通过引用其他文档,这就是population的概念

Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query. Let’s look at some examples.

Population 能够将制定的引用文档自动的替换到主文档中,你可以制定单个文档、多个文档、单个普通对象,多个普通对象,再或者是查询出来的文档

19.1 Schema中建立引用关系

下面我们以【作者-书】为例:

- 作者可能会有多本书

- 每本书仅会归属一个作者(排除:合著情况)

// 定义作者Schema
var AuthorSchema = new Schema({
_id: {type: 'number'},
name: {type: 'string'},
books: [{type: Schema.Types.ObjectId, ref:'book'}]
});

// 定义书Schema
var BookSchema = new Schema({
_author: {type:'number', ref:'author'},
name: {type: 'string'}
});

var AuthorModel = mongoose.model('author', AuthorSchema);
var BookModel = mongoose.model('book', BookSchema);


19.2 保存引用文档的数据

// 创建作者zhagener
var zhagener = new AuthorModel({_id:0,name:'zhagener'});

// 保存作者zhagener
zhagener.save(function(err) {
if (err) {
console.log(err)
}
console.log('save Author successfully')

// 根据作者的_id,继续添加他的第一本书实例
var mongooseInAction = new BookModel({
_author:zhagener._id,
name: 'mongoose in action'
});

// 保存第一本书实例
mongooseInAction.save(function(err) {
if (err) {
console.log(err);
}
console.log('save Book successfully')
})
})


19.2 关联引用文档查询

查询书的所有信息包括作者(所有信息)

BookModel
.findOne({name:'mongoose in action'})
.populate('_author')
.exec(function(err,book) {
if (err) {
console.log(err);
}
console.log(book);
// { _id: 58cb73aaf5e795303808230e,
//   _author: { _id: 0, name: 'zhagener', __v: 0, books: [] },
//   name: 'mongoose in action',
//   __v: 0 }
});


查询书的所有信息包括作者(指定查询域)

BookModel
.findOne({name:'mongoose in action'})
.populate('_author','name')
.exec(function(err,book) {
if (err) {
console.log(err);
}
console.log(book);
// { _id: 58cb73aaf5e795303808230e,
//   _author: { _id: 0, name: 'zhagener' },
//   name: 'mongoose in action',
//   __v: 0 }
});


19.2 关联引用文档更新

BookModel
.findOne({name:'mongoose in action'})
.exec(function(err,book) {
if (err) {
console.log(err);
}
var zhagener2 = new AuthorModel({_id:1,name:'zhagener2'});
book._author = zhagener2;
console.log(book);
// { _id: 58cb73aaf5e795303808230e,
//   _author: { _id: 1, name: 'zhagener2', books: [] },
//   name: 'mongoose in action',
//   __v: 0 }
});


19.3 多个引用文档(保存)

下面我们以【书-作者 书-章节】为例:

- 书对应一个作者

- 作者会有多本书

- 每本书会有很多章节

// 定义作者Schema
var AuthorSchema = new Schema({
_id: {type: 'number'},
name: {type: 'string'},
books: [{type: Schema.Types.ObjectId, ref:'book'}]
});

// 定义书Schema
var BookSchema = new Schema({
_id: {type: 'number'},
_author: {type: 'number', ref:'author'},
name: {type: 'string'},
chapters: [{type: Schema.Types.ObjectId, ref:'chapter'}]
});

// 定义章节Schema
var ChapterSchema = new Schema({
_id: {type: 'number'},
_book: {type: 'number', ref:'chapter'},
title: {type: 'string'},
content: {type: 'string'}
});

var AuthorModel = mongoose.model('author', AuthorSchema);
var BookModel = mongoose.model('book', BookSchema);
var ChapterModel = mongoose.model('chapter', ChapterSchema);

var zhagener = new AuthorModel({_id:0,name:'zhagener'});

// 保存作者zhagener
zhagener.save(function(err) {
if (err) {
console.log(err)
}
console.log('save Author successfully')

// 根据作者的_id,继续添加他的第一本书实例
var mongooseInAction = new BookModel({
_id:0,
_author:zhagener._id,
name: 'mongoose in action'
});

// 保存第一本书实例
mongooseInAction.save(function(err) {
if (err) {
console.log(err);
}
var mongooseIntro = new ChapterModel({
_id: 0,
_book:mongooseInAction._id,
content:'mongoose introduction content'
});
mongooseIntro.save(function(err) {
if (err) {
console.log(err);
}
console.log('save Chapter successfully');
});
console.log('save Book successfully')
});
});


19.4 多个引用文档(查询)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mongodb node.js