Mongoose学习参考文档——基础篇,高级面试问题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文


如果您还不清楚Mongoose是如何工作的,请参看第一章快速通道快速浏览他的用法吧

1. Schema——纯洁的数据库原型

1.1 什么是Schema

  • 我理解Schema仅仅只是一断代码,他书写完成后程序依然无法使用,更无法通往数据库端

  • 他仅仅只是数据库模型在程序片段中的一种表现,或者是数据属性模型

1.2 如何定义Schema


    var BlogSchema = new Schema({

      title:String,

      author:String

      //new Schema()中传入一个JSON对象,该对象形如 xxx:yyyy ,

      /xxx是一个字符串,定义了属性,yyy是一个Schema.Type,定义了属性类型

    });

1.3 什么是Schema.Type

Schema.Type是由Mongoose内定的一些数据类型,基本数据类型都在其中,他也内置了一些Mongoose特有的Schema.Type。当然,你也可以自定义Schema.Type,只有满足Schema.Type的类型才能定义在Schema内。

1.4 Schema.Types

NodeJS中的基本数据类型都属于Schema.Type,另外Mongoose还定义了自己的类型


    //举例:

    var ExampleSchema = new Schema({

      name:String,

      binary:Buffer,

      living:Boolean,

      updated:Date,

      age:Number,

      mixed:Schema.Types.Mixed, //该混合类型等同于nested

      _id:Schema.Types.ObjectId,  //主键

      _fk:Schema.Types.ObjectId,  //外键

      array:[],

      arrOfString:[String],

      arrOfNumber:[Number],

      arrOfDate:[Date],

      arrOfBuffer:[Buffer],

      arrOfBoolean:[Boolean],

      arrOfMixed:[Schema.Types.Mixed],

      arrOfObjectId:[Schema.Types.ObjectId]

      nested:{

        stuff:String,

      }

    });

1.5 关于Buffer

BufferArrayBufferNodejs两种隐藏的对象,相关内容请查看NodeJS-API

1.6 关于Mixed

Schema.Types.MixedMongoose定义个混合类型,该混合类型如果未定义具体形式。因此,如果定义具体内容,就直接使用{}来定义,以下两句等价


    var AnySchema = new Schema({any:{}});

    var AnySchema = new Schema({any:Schema.Types.Mixed});

混合类型因为没有特定约束,因此可以任意修改,一旦修改了原型,则必须调用markModified()


    person.anything = {x:[3,4,{y:'change'}]}

    person.markModified('anything');//传入anything,表示该属性类型发生变化

    person.save();

1.7 关于ObjectId

主键,一种特殊而且非常重要的类型,每个Schema都会默认配置这个属性,属性名为_id,除非自己定义,方可覆盖


    var mongoose = require('mongoose');

    var ObjectId = mongoose.Schema.Types.ObjectId;

    var StudentSchema = new Schema({}); //默认会有_id:ObjectId

    var TeacherSchema = new Schema({id:ObjectId});//只有id:ObjectId

该类型的值由系统自己生成,从某种意义上几乎不会重复,生成过程比较复杂,有兴趣的朋友可以查看源码。

1.8 关于Array

ArrayJavaScript编程语言中并不是数组,而是集合,因此里面可以存入不同的值,以下代码等价:


    var ExampleSchema1 = new Schema({array:[]});

    var ExampleSchema2 = new Schema({array:Array});

    var ExampleSchema3 = new Schema({array:[Schema.Types.Mixed]});

    var ExampleSchema4 = new Schema({array:[{}]});

1.9 附言

Schema不仅定义了文档结构使用性能,还可以有扩展插件实例方法静态方法复合索引文档生命周期钩子

Schema可以定义插件,并且插件具有良好的可拔插性,请有兴趣的读者继续往后阅读或者查阅官方资料。

2. Schema的扩展

2.1 实例方法

有的时候,我们创造的Schema不仅要为后面的ModelEntity提供公共的属性,还要提供公共的方法。

下面例子比快速通道的例子更加高级,可以进行高级扩展:


    var PersonSchema = new Schema({name:String,type:String});

    //查询类似数据

    PersonSchema.methods.findSimilarTypes = function(cb){

      return this.model('Person').find({type:this.type},cb);

    }

使用如下:


    var PersonModel = mongoose.model('Person',PersonSchema);

    var krouky = new PersonModel({name:'krouky',type:'前端工程师'});

    krouky.findSimilarTypes(function(err,persons){

      //persons中就能查询到其他前端工程师

    });

2.2 静态方法

静态方法在Model层就能使用,如下:


  PersonSchema.statics.findByName = function(name,cb){

    this.find({name:new RegExp(name,'i'),cb});

  }

  var PersonModel = mongoose.model('Person',PersonSchema);

  PersonModel.findByName('krouky',function(err,persons){

    //找到所有名字叫krouky的人

  });

2.3 索引

索引或者复合索引能让搜索更加高效,默认索引就是主键索引ObjectId,属性名为_id, 索引会作为一个专题来讲解

2.4 虚拟属性

Schema中如果定义了虚拟属性,那么该属性将不写入数据库,例如:


    var PersonSchema = new Schema({

      name:{

        first:String,

        last:String

      }

    });

    var PersonModel = mongoose.model('Person',PersonSchema);

    var krouky = new PersonModel({

      name:{first:'krouky',last:'han'}

    });

如果每次想使用全名就得这样


    console.log(krouky.name.first + ' ' + krouky.name.last);

显然这是很麻烦的,我们可以定义虚拟属性


    PersonSchema.virtual('name.full').get(function(){

      return this.name.first + ' ' + this.name.last;

    });

那么就能用krouky.name.full来调用全名了,反之如果知道full,也可以反解firstlast属性


    PersonSchema.virtual('name.full').set(function(name){

      var split = name.split(' ');

      this.name.first = split[0];

      this.name.last = split[1];

    });

    var PersonModel = mongoose.model('Person',PersonSchema);

    var krouky = new PersonModel({});

    krouky.name.full = 'krouky han';//会被自动分解

    console.log(krouky.name.first);//krouky

2.5 配置项

在使用new Schema(config)时,我们可以追加一个参数options来配置Schema的配置,形如:


    var ExampleSchema = new Schema(config,options);

或者使用


    var ExampleSchema = new Schema(config);

    ExampleSchema.set(option,value);

可供配置项有:safestrictcappedversionKeyautoIndex

2.5.1 safe——安全属性(默认安全)

一般可做如下配置:


    new Schema({...},{safe:true});

当然我们也可以这样


    new Schema({...},{safe:{j:1,w:2,wtimeout:10000}});

j表示做1份日志,w表示做2个副本(尚不明确),超时时间10秒

2.5.2 strict——严格配置(默认启用)

确保Entity的值存入数据库前会被自动验证,如果你没有充足的理由,请不要停用,例子:


    var ThingSchema = new Schema({a:String});

    var ThingModel = db.model('Thing',SchemaSchema);

    var thing = new Thing({iAmNotInTheThingSchema:true});

    thing.save();//iAmNotInTheThingSchema这个属性将无法被存储

如果取消严格选项,iAmNotInTheThingSchema将会被存入数据库

该选项也可以在构造实例时使用,例如:


    var ThingModel = db.model('Thing');

    var thing1 = new ThingModel(doc,true);  //启用严格

    var thing2 = new ThingModel(doc,false); //禁用严格

注意:

strict也可以设置为throw,表示出现问题将会抛出错误

2.5.3 shardKey

需要mongodb做分布式,才会使用该属性

2.5.4 capped——上限设置

如果有数据库的批量操作,该属性能限制一次操作的量,例如:


    new Schema({...},{capped:1024});  //一次操作上线1024条数据

当然该参数也可是JSON对象,包含size、max、autiIndexId属性


    new Schema({...},{capped:{size:1024,max:100,autoIndexId:true}});

2.5.5 versionKey——版本锁

版本锁是Mongoose默认配置(__v属性)的,如果你想自己定制,如下:


    new Schema({...},{versionKey:'__someElse'});

此时存入数据库的版本锁就不是__v属性,而是__someElse,相当于是给版本锁取名字。

具体怎么存入都是由MongooseMongoDB自己决定,当然,这个属性你也可以去除


  new Schema({...},{versionKey:false});

除非你知道你在做什么,并且你知道这样做的后果

2.5.6 autoIndex——自动索引

该内容将在索引章节单独讲解

3. Documents

Document是与MongoDB文档一一对应的模型,Document可等同于Entity,具有属性和操作性

注意:

Document的`CRUD都必须经过严格验证的,参看2.5.2 Schema的strict严格配置

3.1 查询

查询内容过多,专题讲解

3.2 更新

有许多方式来更新文件,以下是常用的传统方式:


    PersonModel.findById(id,function(err,person){

      person.name = 'MDragon';

      person.save(function(err){});

    });

这里,利用Model模型查询到了person对象,该对象属于Entity,可以有save操作,如果使用Model`操作,需注意:


    PersonModel.findById(id,function(err,person){

      person.name = 'MDragon';

      var _id = person._id; //需要取出主键_id

      delete person._id;    //再将其删除

      PersonModel.update({_id:_id},person,function(err){});

      //此时才能用Model操作,否则报错

    });

update第一个参数是查询条件,第二个参数是更新的对象,但不能更新主键,这就是为什么要删除主键的原因。

当然这样的更新很麻烦,可以使用$set属性来配置,这样也不用先查询,如果更新的数据比较少,可用性还是很好的:


    PersonModel.update({_id:_id},{$set:{name:'MDragon'}},function(err){});

需要注意,DocumentCRUD操作都是异步执行,callback第一个参数必须是err,而第二个参数各个方法不一样,updatecallback第二个参数是更新的数量,如果要返回更新后的对象,则要使用如下方法


    Person.findByIdAndUpdate(_id,{$set:{name:'MDragon'}},function(err,person){

      console.log(person.name); //MDragon

    });

类似的方法还有findByIdAndRemove,如同名字,只能根据id查询并作update/remove操作,操作的数据仅一条

3.3 新增

如果是Entity,使用save方法,如果是Model,使用create方法


    //使用Entity来增加一条数据

    var krouky = new PersonModel({name:'krouky'});

    krouky.save(callback);

    //使用Model来增加一条数据

    var MDragon = {name:'MDragon'};

    PersonModel.create(MDragon,callback);

两种新增方法区别在于,如果使用Model新增时,传入的对象只能是纯净的JSON对象,不能是由Model创建的实体,原因是:由Model创建的实体krouky虽然打印是只有{name:'krouky'},但是krouky属于Entity,包含有Schema属性和Model数据库行为模型。如果是使用Model创建的对象,传入时一定会将隐藏属性也存入数据库,虽然3.x追加了默认严格属性,但也不必要增加操作的报错

3.4 删除

和新增一样,删除也有2种方式,但EntityModel都使用remove方法

4.Sub Docs

如同SQL数据库中2张表有主外关系,Mongoose将2个Document的嵌套叫做Sub-Docs(子文档)

简单的说就是一个Document嵌套另外一个Document或者Documents:


    var ChildSchema1 = new Schema({name:String});

    var ChildSchema2 = new Schema({name:String});

    var ParentSchema = new Schema({

      children1:ChildSchema1,   //嵌套Document

      children2:[ChildSchema2]  //嵌套Documents

    });

Sub-Docs享受和Documents一样的操作,但是Sub-Docs的操作都由父类去执行


    var ParentModel = db.model('Parent',parentSchema);

    var parent = new ParentModel({

      children2:[{name:'c1'},{name:'c2'}]

    });

    parent.children2[0].name = 'd';

    parent.save(callback);

parent在执行保存时,由于包含children2,他是一个数据库模型对象,因此会先保存chilren2[0]chilren2[1]

如果子文档在更新时出现错误,将直接报在父类文档中,可以这样处理:


    ChildrenSchema.pre('save',function(next){

      if('x' === this.name) return next(new Error('#err:not-x'));

      next();

    });

    var parent = new ParentModel({children1:{name:'not-x'}});

    parent.save(function(err){

      console.log(err.message); //#err:not-x

    });

4.1 查询子文档

如果childrenparent的子文档,可以通过如下方法查询到children


    var child = parent.children.id(id);

4.2 新增、删除、更新

子文档是父文档的一个属性,因此按照属性的操作即可,不同的是在新增父类的时候,子文档是会被先加入进去的。

如果ChildrenSchema是临时的一个子文档,不作为数据库映射集合,可以这样:


    var ParentSchema = new Schema({

      children:{

        name:String

      }

    });

    //其实就是匿名混合模式

5.Model

5.1 什么是Model

Model模型,是经过Schema构造来的,除了Schema定义的数据库骨架以外,还具有数据库行为模型,他相当于管理数据库属性、行为的类

5.2 如何创建Model

你必须通过Schema来创建,如下:


    //先创建Schema

    var TankSchema = new Schema({

      name:'String',

      size:'String' 

    });

    //通过Schema创建Model

    var TankModel = mongoose.model('Tank',TankSchema);


## 最后

都说三年是程序员的一个坎,能否晋升或者提高自己的核心竞争力,这几年就十分关键。

**技术发展的这么快,从哪些方面开始学习,才能达到高级工程师水平,最后进阶到Android架构师/技术专家?我总结了这 5大块;**

 > 我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 PDF(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

>![](https://img-blog.csdnimg.cn/img_convert/60c6a58c1558a34b83a9f97ee4295bf3.webp?x-oss-process=image/format,png)

 **Java语言与原理;**
大厂,小厂。Android面试先看你熟不熟悉Java语言

> ![](https://img-blog.csdnimg.cn/img_convert/e62fd3757d6357effa6f9a8c31b695c0.webp?x-oss-process=image/format,png)

**高级UI与自定义view;**
自定义view,Android开发的基本功。

> ![](https://img-blog.csdnimg.cn/img_convert/44821de5c12ea362c1c29e187b622a0b.webp?x-oss-process=image/format,png)

**性能调优;**
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。

> ![](https://img-blog.csdnimg.cn/img_convert/5c9168870074b700f09e4ebb682a2e77.webp?x-oss-process=image/format,png)

**NDK开发;**
未来的方向,高薪必会。

> ![](https://img-blog.csdnimg.cn/img_convert/f4047d7f82f0e8c92d41a3ed372361d0.webp?x-oss-process=image/format,png)

**前沿技术;**
组件化,热升级,热修复,框架设计

> ![](https://img-blog.csdnimg.cn/img_convert/da01fb76bdfca6806c8efb08b586dc5d.webp?x-oss-process=image/format,png)

> 网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。

**不出半年,你就能看出变化!**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)**
![img](https://img-blog.csdnimg.cn/img_convert/79f193f0903fb1f18aaaa47b286032f1.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

.(img-wcjJMrGq-1713564164956)]

 **Java语言与原理;**
大厂,小厂。Android面试先看你熟不熟悉Java语言

> [外链图片转存中...(img-o24r2yVP-1713564164956)]

**高级UI与自定义view;**
自定义view,Android开发的基本功。

> [外链图片转存中...(img-WYltBTeH-1713564164957)]

**性能调优;**
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。

> [外链图片转存中...(img-egX8Rk1I-1713564164957)]

**NDK开发;**
未来的方向,高薪必会。

> [外链图片转存中...(img-mLdVVV9k-1713564164957)]

**前沿技术;**
组件化,热升级,热修复,框架设计

> [外链图片转存中...(img-4mZx7g7i-1713564164958)]

> 网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多

当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。

**不出半年,你就能看出变化!**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)**
[外链图片转存中...(img-TMesOsGp-1713564164958)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 29
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值