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 多个引用文档(查询)
相关文章推荐
- MONGOOSE – 让NODE.JS高效操作MONGODB(转载)
- mongoose - 让node.js高效操作mongodb
- nodejs+mongoose操作mongodb副本集实例
- Mongoose配合Node.js操作MongoDB的基础教程
- node.js学习笔记(二)--使用mongoose简单的CRUD操作及测试模块mocha的使用
- 安装使用Mongoose配合Node.js操作MongoDB的基础教程
- mongoose - 让node.js高效操作mongodb
- 使用node.js的第三方模块Mongoose访问mongodb(六)
- nodejs mongoose 操作mongodb 数据库封装
- 安装使用Mongoose配合Node.js操作MongoDB的基础教程
- 分针网—每日分享:安装使用Mongoose配合Node.js操作MongoDB的基础教程
- Node.Js Path模块-文件或文件夹路径字符串操作
- node.js零基础详细教程(7):node.js操作mongodb,及操作方法的封装
- Node.Js fs模块文件操作(一)
- Node.Js fs模块文件操作(三)
- node.js操作mongodb简单示例分享
- Node.js+jade+mongodb+mongoose实现爬虫分离入库与生成静态文件的方法
- Node.js对于MongoDB的操作DAO的封装
- Node.js开发——添加mongoose模块引发的异常
- 使用node.js中的async模块进行数据库的同步操作