zoukankan      html  css  js  c++  java
  • Mongoose全面理解

    Mongoose全面理解

    一、创建schemas

    创建schemas的方式:

    1 var userSchema = new mongoose.Schema({
    2     name: String,
    3     email: String,
    4     createdOn: Date
    5 });

    schemas中的数据类型有以下几种:
    • String
    • Number
    • Date
    • Boolean
    • Buffer
    • ObjectId
    • Mixed
    • Array

    特别需要说明一下ObjectId类型和Mixed类型以及Array类型,在schemas中声明这几种类型的方式如下:

     1 //ObjectId就类似于唯一键值
     2 projectSchema.add({
     3     owner: mongoose.Schema.Types.ObjectId
     4 });
     5 //混合类型,顾名思义,就是说里面可以放置任意类型的数据,有两种方式创建该类型数据
     6 //方式一:直接赋予一个空的字面量对象
     7 vardjSchema= new mongoose.Schema({
     8     mixedUp: {}
     9 });
    10 //方式二:根据Schemas.Types中值来赋予
    11 vardjSchema= new mongoose.Schema({
    12     mixedUp: Schema.Types.Mixed
    13 });
    14 //Array类型数据有两种创建方式,一种是简单数组创建:
    15 var userSchema = new mongoose.Schema({
    16     name: String,
    17     emailAddresses: [String]
    18 });
    19 //第二种方式就是复杂类型数据数组,例如我们可以再数组中添加不同类型的schemas:
    20 var emailSchema = new mongoose.Schema({
    21     email: String,
    22     verified: Boolean
    23 });
    24 var userSchema = new mongoose.Schema({
    25     name: String,
    26     emailAddresses: [emailSchema]
    27 });
    28 //注意:如果定义一个空的数据的话,则会创建为一个混合类型数据的数组:
    29 var emailSchema = new mongoose.Schema({
    30     email: String,
    31     verified: Boolean
    32 });
    33 var userSchema = new mongoose.Schema({
    34     name: String,
    35     emailAddresses: [emailSchema]
    36 });

    我们可以给schema创建静态方法,这个静态方法将来会用在Model中,创建该静态方法需要在创建完成schema之后,在Model编译之前:

    1 projectSchema.statics.findByUserID = function (userid, callback) {
    2   this.find({ createdBy: userid }, '_id projectName', {sort: 'modifiedOn'}, callback);
    3 };

    在其对应的模型创建完成并编译后,我们就可以像下面这样来调用该静态方法了:
    Model.findByUserID(userid,callback);
    该静态方法会返回一个JSON格式的数据,这在我们使用AJAX技术来加载网页数据的时候会比较方便,就像下面这样:

     1 //路由规则:app.get('/project/byuser/:userid', project.byUser);
     2 exports.byUser = function (req, res) {
     3     console.log("Getting user projects");
     4     if (req.params.userid){
     5         Project.findByUserID(req.params.userid,function (err, projects) {
     6             if(!err){
     7                 console.log(projects);
     8                 res.json(projects);
     9             }else{
    10                 console.log(err);
    11                 res.json({"status":"error", "error":"Error finding projects"});
    12             }
    13         });
    14     }else{
    15         console.log("No user id supplied");
    16         res.json({"status":"error", "error":"No user id supplied"});
    17     }
    18 };

    二、创建Model

    创建Model很简单:
    Mongoose.Model('User', userSchema);
    参数一为Model的名字,参数二为生成Model所需要的schema,Model就像是schema所编译而成的一样。
    mongoose连接数据库是有两种方式的:

     1 //方式一:
     2 var dbURI = 'mongodb://localhost/mydatabase';
     3 mongoose.connect(dbURI);
     4 //方式二:
     5 var dbURI = 'mongodb://localhost/myadmindatabase';
     6 var adminConnection = mongoose.createConnection(dbURI);
     7 //如果需要声明端口号:
     8 var dbURI = 'mongodb://localhost:27018/mydatabase';
     9 //如果需要定义用户名和密码:
    10 var dbURI = 'mongodb://username:password@localhost/mydatabase';
    11 //也可以像下面这样传一个对象类型的参数:
    12 var dbURI = 'mongodb://localhost/mydatabase';
    13 var dbOptions = {'user':'db_username','pass':'db_password'};
    14 mongoose.connect(dbURI, dbOptions);

    根据连接数据库的方式,我们可以得到第二种创建Model的方式,就是使用数据库连接的引用名来创建:
    adminConnection.model( 'User', userSchema );

    默认情况下mongoose会根据我们传入的Model名字来生成collection名字,在上面的代码中就会生成名为users(全为小写字母)的collection(集合);
    有两种方法能让我们自定义collection的名字。

     1 //方式一,在创建schema的时候定义collection的名字:
     2 var userSchema = new mongoose.Schema({
     3     name: String,
     4     email: {type: String, unique:true}
     5 },
     6 {
     7     collection: 'myuserlist'
     8 });
     9 //方式二,在创建Model的时候定义collection的名字:
    10 mongoose.model( 'User', userSchema, 'myuserlist' );

    创建Model实例:
    var user = new User({ name: 'Simon' });
    user就是模型User的一个实例,它具有mongoose中模型所具有的一些方法,例如保存实例:

    1 user.save(function (err) {
    2     if (err) return handleError(err);
    3 });

    模型也具有一些常用的增删查改的方法:

     1 User.findOne({'name' : 'Sally', function(err,user) {
     2     if(!err){
     3         console.log(user);
     4     }
     5 });
     6 User.find({}, function(err, users) {
     7     if(!err){
     8         console.log(users);
     9     }
    10 });

    可以使用链式方式使用这些方法,例如:

    1 var newUser = new User({
    2     name: 'Simon Holmes',
    3     email: 'simon@theholmesoffice.com',
    4     lastLogin : Date.now()
    5 }).save( function( err ){
    6     if(!err){
    7         console.log('User saved!');
    8     }
    9 });

    上面的代码创建了一个模型实例,然后进行保存。我们有一个更为简介的方式来完成这项工作,就是使用Model.create()方法:

     1 User.create({
     2     name: 'Simon Holmes',
     3     email: 'simon@theholmesoffice.com',
     4     lastLogin : Date.now()
     5 }, function( err, user ){
     6     if(!err){
     7         console.log('User saved!');
     8         console.log('Saved user name: ' + user.name);
     9         console.log('_id of saved user: ' + user._id);
    10     }
    11 });

    三、查找数据和读取数据的方法

    1.使用QueryBuilder接口来查找数据
    先看看下面的代码:

    1 var myQuery = User.find({'name' : 'Simon Holmes'});
    2 myQuery.where('age').gt(18);
    3 myQuery.sort('-lastLogin');
    4 myQuery.select('_id name email');
    5 myQuery.exec(function (err, users){
    6     if (!err){
    7         console.log(users); // output array of users found
    8     }
    9 });

    代码中,我们查找名字为"Simon Holmes",并且年龄大于18岁,查找结果根据lastLogin降序排列,只获取其中的_id, name, email三个字段的值,上面的代码只有在调用exec方法后才真正执行数据库的查询。
    当然我们可以使用链式的方式来改写上面的代码,代码会更加简洁:

    1 User.find({'name' : 'Simon Holmes'})
    2 .where('age').gt(18)
    3 .sort('-lastLogin')
    4 .select('_id name email')
    5 .exec(function (err, users){
    6     if (!err){
    7         console.log(users); // output array of users found
    8     }
    9 });

    上面代码中的第一行创建了一个queryBuilder.通过使用这个queryBuilder,我们就可以执行一些比较复杂的查找工作,
    在创建完成这个queryBuilder之后,查询操作并没有马上执行,而是待到执行exec方法时才会去执行数据库的查找。
    当然也有另外一种方式能够直接查找数据库的,就是直接在查找方法中添加回调函数,使用方式为:
    Model.find(conditions, [fields], [options], [callback])
    下面举一个简单例子:

    1 User.find({'name', 'simon holmes'}, function(err, user) {});

    另一个稍微复杂的例子:

    1 User.find({'name', 'simon holmes'}, 'name email',function(err, user) {
    2     //console.log('some thing');
    3 });

    另一个更加复杂的例子,包含查询结果的排序:

    1 User.find({'name' : 'Simon Holmes'},
    2     null, // 如果使用null,则会返回所有的字段值
    3     {sort : {lastLogin : -1}}, // 降序排序
    4     function (err, users){
    5         if (!err){console.log(users);}
    6     });

    列举几个比较实用的查找方法:

    1 Model.find(query);
    2 Model.findOne(query);//返回查找到的所有实例的第一个
    3 Model.findById(ObjectID);//根据ObjectId查找到唯一实例

    例如:

    1 User.findOne({'email' : req.body.Email},
    2 '_id name email',
    3 function(err, user) {
    4     //todo
    5 });

    2.更新数据
    有三种方式来更新数据:
    (1)update(conditions,update,options,callback);
    该方法会匹配到所查找的内容进行更新,不会返回数据;
    (2)findOneAndUpdate(conditions,update,options,callback);
    该方法会根据查找去更新数据库,另外也会返回查找到的并未改变的数据;
    (3)findByIdAndUpdate(conditions,update,options,callback);
    该方法跟上面的findOneAndUpdate方法功能一样,不过他是根据ID来查找文档并更新的。

    三个方法都包含四个参数,一下稍微说明一下几个参数的意思:
    conditions:查询条件
    update:更新的数据对象,是一个包含键值对的对象
    options:是一个声明操作类型的选项,这个参数在下面再详细介绍
    callback:回调函数

    对于options参数,在update方法中和findOneAndUpdate、findByIdAndUpdate两个方法中的可选设置是不同的;

     1 //在update方法中,options的可选设置为:
     2 {
     3 safe:true|false,  //声明是否返回错误信息,默认true
     4 upsert:false|true, //声明如果查询不到需要更新的数据项,是否需要新插入一条记录,默认false
     5 multi:false|true,  //声明是否可以同时更新多条记录,默认false
     6 strict:true|false  //声明更新的数据中是否可以包含在schema定义之外的字段数据,默认true
     7 }
     8 //对于findOneAndUpdate、findByIdAndUpdate这两个方法,他们的options可选设置项为:
     9 {
    10 new:true|false, //声明返回的数据时更新后的该是更新前的,如果为true则返回更新后的,默认true
    11 upsert:false|trure, 
    12 sort:javascriptObject, //如果查询返回多个文档记录,则可以进行排序,在这里是根据传入的javascript object对象进行排序
    13 select:String //这里声明要返回的字段,值是一个字符串
    14 }

    下面举个例子:

    1 User.update({_id:user._id},{$set: {lastLogin: Date.now()}},function(){});

    3.数据删除
    跟更新数据一样,也有三种方法给我们删除数据:
    remove();
    findOneAndRemove();
    findByIdAndRemove();
    remove方法有两种使用方式,一种是用在模型上,另一种是用在模型实例上,例如:

     1 User.remove({ name : /Simon/ } , function (err){
     2     if (!err){
     3         // 删除名字中包含simon的所有用户
     4     }
     5 });
     6 
     7 User.findOne({ email : 'simon@theholmesoffice.com'},function (err,user){
     8     if (!err){
     9         user.remove( function(err){
    10             // 删除匹配到该邮箱的第一个用户
    11         });
    12     }
    13 });

    接下来看一下findOneAndRemove方法:

    1 User.findOneAndRemove({name : /Simon/},{sort : 'lastLogin', select : 'name email'},function (err, user){
    2     if (!err) {
    3         console.log(user.name + " removed");
    4         // Simon Holmes removed
    5     };
    6 });

    另外一个findByIdAndRemove方法则是如出一辙的。

    1 User.findByIdAndRemove(req.body._id,function (err, user) {
    2     if(err){
    3         console.log(err);
    4         return;
    5     }
    6     console.log("User deleted:", user);
    7 });

    四、数据验证

    1.mongoose内置数据验证
    在mongoose中,数据验证这一层是放在schema中的,mongoose已经帮我们做了很多内置的数据验证,有一些验证是针对某些数据类型的,也有一些是针对所有数据类型的。
    能够作用在所有数据类型上的验证有require,意思就是该字段是否是必须的,例如:
    email: { type: String, unique: true, required: true }
    上面的代码就定义了一个email是必须的schema.
    下面再分别介绍一下mongoose内置的一些数据验证类型。


    数字类型schemasType,对于Number类型的数据,具有min,max提供用来界定最大最小值:

    1 var teenSchema = new Schema({
    2     age : {type: Number, min: 13, max:19}
    3 });

    字符串类型SchemasType,对于该类型数据,mongoose提供了两种验证器:
    match:可使用正则表达式来匹配字符串是否符合该正则表达式的规则
    enum:枚举出字符串可使用的一些值
    分别举例如下:

    1 var weekdaySchema = new Schema({
    2     day : {type: String, match: /^(mon|tues|wednes|thurs|fri)day$/i}
    3 });
    4 
    5 var weekdays = ['monday', 'tuesday', 'wednesday', 'thursday','friday'];
    6 var weekdaySchema = new Schema({
    7     day : {type: String, enum: weekdays}
    8 });

    在我们进行一些数据库的时候,如果有错误,可能会返回一些错误信息,这些信息封装在一个对象中,该对象的数据格式大致如下:

     1 { 
     2     message: 'Validation failed',
     3     name: 'ValidationError',
     4     errors:{ 
     5         email:{
     6             message: 'Validator "required" failed for path email',
     7             name: 'ValidatorError',
     8             path: 'email',
     9             type: 'required' 
    10         },
    11         name:{ 
    12             message: 'Validator "required" failed for path name',
    13             name: 'ValidatorError',
    14             path: 'name',
    15             type: 'required' 
    16         } 
    17     } 
    18 }

    知道该错误信息的具体格式之后,我们可以从中得出我们想要的信息并反馈到控制台。

    1 if(err){
    2     Object.keys(err.errors).forEach(function(key) {
    3         var message = err.errors[key].message;
    4         console.log('Validation error for "%s": %s', key, message);
    5     });
    6 }

    2.自定义数据验证
    最简单的自定义数据验证方式就是定义一个数据验证的函数,并将它传递给schema;

    1 var lengthValidator = function(val) {
    2     if (val && val.length >= 5){
    3         return true;
    4     }
    5     return false;
    6 };
    7 //usage:
    8 name: {type: String, required: true, validate: lengthValidator }

    可以看到,我们只需要在schema中添加validate键值对即可,validate对应的值便是我们自定义的验证方法;
    但是该形式的数据验证无法给我们提供完整的错误信息,比如errors信息中返回的type值就会成为undefined;
    在此基础上如果希望错误信息中能返回一个错误描述,那我们可以稍微进行一点修改:

    1 //code 1
    2 validate: { validator: lengthValidator, msg: 'Too short' }
    3 
    4 //code 2
    5 var weekdaySchema = new Schema({
    6     day : {type: String, validate: {validator:/^(mon|tues|wednes|thurs|fri)day$/i, msg: 'Not a day' }
    7 });

    将validate的值修改为一个对象,并且该对象包含验证器和错误描述。
    我们也可以使用另一种方式在写这些验证器,就是将验证器卸载schema外部,例如:

    1 var validateLength = [lengthValidator, 'Too short' ];
    2 var validateDay = [/^(mon|tues|wednes|thurs|fri)day$/i, 'Not a day' ];
    3 //usage:
    4 name: {type: String, required: true, validate: validateLength }
    5 day : {type: String, validate: validateDay }

    眼睛放大,一看再看,确实没错,在validate中我们传入的是一个数组了,而不是原来的对象了。
    其实就validateLength这个东东来说,他就是一个简写来的,你也可以改成下面这样:

    1 var validateLength = [
    2     {validator: lengthValidator, msg: 'Too short'}
    3 ];

    恩,到这里,应该能明白了,将对象改为数组之后,我们便可以传递多个验证器给我们的schema了,的确如此。

    1 var validateUsername = [
    2     {validator: lengthValidator, msg: 'Too short'} ,
    3     {validator: /^[a-z]+$/i, msg: 'Letters only'}
    4 ];

    我们还有另外一种方法给我们的schema提供验证器:

    1 userSchema.path('name').validate(lengthValidator, 'Too short');
    2 userSchema.path('name').validate(/^[a-z]+$/i, 'Letters only');

    参考《mongoose for application development》

  • 相关阅读:
    例题6-8 Tree Uva548
    例题6-7 Trees on the level ,Uva122
    caffe Mac 安装
    Codeforces Round #467 (Div. 1) B. Sleepy Game
    Educational Codeforces Round37 E
    Educational Codeforces Round 36 (Rated for Div. 2) E. Physical Education Lessons
    Good Bye 2017 E. New Year and Entity Enumeration
    Good Bye 2017 D. New Year and Arbitrary Arrangement
    Codeforces Round #454 D. Seating of Students
    浙大紫金港两日游
  • 原文地址:https://www.cnblogs.com/moyiqing/p/mongoose.html
Copyright © 2011-2022 走看看