怎么理解 Mongoose 的 pre 中间件概念的理解,还有 path

8580人阅读
Mongoose学习参考文档
前言:本学习参考文档仅供参考,如有问题,师请雅正
一、快速通道
&###1.1 名词解释
&&Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
&&Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
&&Entity : 由Model创建的实体,他的操作也会影响数据库
&&1. 本学习文档采用严格命名方式来区别不同对象,例如:
var PersonSchema;
//Person的文本属性
var PersonModel;
//Person的数据库模型
var PersonEntity;
//Person实体
&&2. Schema、Model、Entity的关系请牢记,Schema生成Model,Model创
造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操
&###1.2 准备工作
&&1. 首先你必须安装和
&&2. 在项目只能够创建一个数据库连接,如下:
var mongoose = require('mongoose');
//引用mongoose模块
var db = mongoose.createConnection('localhost','test'); //创
建一个数据库连接
&&3. 打开本机localhost的test数据库时,我们可以监测是否有异常
db.on('error',console.error.bind(console,'连接错误:'));
db.once('open',function(){
//一次打开记录
&&注意:成功开启数据库后,就可以执行数据库相应操作,假设以下代码都
在回调中处理
&&4. 定义一个Schema
var PersonSchema = new mongoose.Schema({
name:String
//定义一个属性name,类
型为String
&&5. 将该Schema发布为Model
var PersonModel = db.model('Person',PersonSchema);
//如果该Model已经发布,则可以直接通过名字索引到,如下:
//var PersonModel = db.model('Person');
//如果没有发布,上一段代码将会异常
&&6. 用Model创建Entity
var personEntity = new PersonModel({name:'Krouky'});
//打印这个实体的名字看看
console.log(personEntity.name); //Krouky
&&7. 我们甚至可以为此Schema创建方法
//为Schema模型追加speak方法
PersonSchema.methos.speak = function(){
console.log('我的名字叫'+this.name);
var PersonModel = db.model('Person',PersonSchema);
var personEntity = new PersonModel({name:'Krouky'});
personEntity.speak();//我的名字叫Krouky
&&8. Entity是具有具体的数据库操作CRUD的
personEntity.save();
//执行完成后,数据库就有该数据了
&&9. 如果要执行查询,需要依赖Model,当然Entity也是可以做到的
PersonModel.find(function(err,persons){
//查询到的所有person
&& 1. 具体的如何配置Schema、Model以及Model和Entity的相关操作,我们
会在后面进行
&& 2. Model和Entity都有能影响数据库的操作,但仍有区别,后面我们也会做
二、新手指引
&*如果您还不清楚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,
//该混合类型等同于
_id:Schema.Types.ObjectId,
_fk:Schema.Types.ObjectId,
arrOfString:[String],
arrOfNumber:[Number],
arrOfDate:[Date],
arrOfBuffer:[Buffer],
arrOfBoolean:[Boolean],
arrOfMixed:[Schema.Types.Mixed],
arrOfObjectId:[Schema.Types.ObjectId]
stuff:String,
&& ####1.5 关于Buffer
&&& Buffer和ArrayBuffer是Nodejs两种隐藏的对象,相关内容请查看
NodeJS-API
&& ####1.6 关于Mixed
&&& Schema.Types.Mixed是Mongoose定义个混合类型,该混合类型如果未定
义具体形式,用此。
&&& 如果定义具体内容,就直接使用{}来定义,一下两句等同
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
&&& Array在JavaScript编程语言中并不是数组,而是集合,因此里面可以存入不
同的值,以下代码等价:
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不仅要为后面的Model和Entity提供公共的
属性,还要提供公共的方法
&&& 下面例子比快速通道的例子更加高级,可以进行高级扩展:
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 PersonSchema({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({
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,也可以反解
first和last
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);
&&& 可供配置项有:safe、strict、capped、versionKey、
&&& #####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,相当于是给
版本锁取名字
&&&& 具体怎么存入都是由Mongoose和MongoDB自己决定,当然,这个属
性你也可以去除
new Schema({...},{versionKey:false});
&&&& 除非你知道你在做什么,并且你知道这样做的后果
&&& #####2.5.6 autoIndex——自动索引
&&&&&该内容将在索引章节单独讲解
& ###3. Documents
&& Document是与MongoDB文档一一对应的模型,Document可等同于Entity
,具有属性和操作性
&& 注意:Document的CRUD都必须经过严格验证的,参看2.5.2Schema的
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
&&&& 需要注意,Document的CRUD操作都是异步执行,callback第一个参数
必须是err,而第二个参数各个方法不一样,update的callback第二个参数是更新
的数量,如果要返回更新后的对象,则要使用如下方法
Person.findByIdAndUpdate(_id,{$set:{name:'MDragon'}},function
(err,person){
console.log(person.name);
&&&& 类似的方法还有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种方式,但Entity和Model都使用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,
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-
var parent = new ParentModel({children1:{name:'not-x'}});
parent.save(function(err){
console.log(err.message);
//#err:not-x
&& ####4.1 查询子文档
&&& 如果children是parent的子文档,可以通过如下方法查询到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);
&& ####5.2 操作Model
&&& 该模型就能直接拿来操作,具体查看API,例如:
var tank = {'something',size:'small'};
TankModel.create(tank);
&&& 注意:你可以使用Model来创建Entity,Entity实体是一个特有Model具体
对象,但是他并不具备Model的方法,只能用自己的方法
//通过Model创建Entity
var tankEntity = new TankModel('someother','size:big');
tankEntity.save();
& ###6.Query
&& 查询是数据库中运用最多也是最麻烦的地方,这里对Query解读的并不完善,
仅仅是自己的一点领悟而已
&& ####6.1 查询的方式
&& 通常有2种查询方式,一种是直接查询,一种是链式查询(2种查询都是自己命
&&& #####6.1.1 直接查询
&&&& 在查询时带有回调函数的,称之为直接查询,查询的条件往往通过API来
设定,例如:
PersonModel.findOne({'name.last':'dragon'},'some select',function
(err,person){
//如果err==null,则person就能取到数据
&&&& 具体的查询参数,请查询API
&&& #####6.1.2 链式查询
&&&& 在查询时候,不带回调,而查询条件通过API函数来制定,例如:
var query = PersonModel.findOne({'name.last':'dragon'});
query.select('some select');
query.exec(function(err,pserson){
//如果err==null,则person就能取到数据
&&&& 这种方式相对直接查询,分的比较明细,如果不带callback,则返回
query,query没有执行的预编译查询语句,该query对象执行的方法都将返回自
己,只有在执行exec方法时才执行查询,而且必须有回调。
&&&& 因为query的操作始终返回自身,我们可以采用更形象的链式写法
.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);
& ###7.Validation
&& 数据的存储是需要验证的,不是什么数据都能往数据库里丢或者显示到客户
端的,数据的验证需要记住以下规则:
&&& - 验证始终定义在SchemaType中
&&& - 验证是一个内部中间件
&&& - 验证是在一个Document被保存时默认启用的,除非你关闭验证
&&& - 验证是异步递归的,如果你的SubDoc验证失败,Document也将无法保存
&&& - 验证并不关心错误类型,而通过ValidationError这个对象可以访问
&& ####7.1 验证器
&&& 1. required 非空验证
&&& 2. min/max 范围验证(边值验证)
&&& 3. enum/match 枚举验证/匹配验证
&&& 4. validate 自定义验证规则
&& 以下是综合案例:
var PersonSchema = new Schema({
type:'String',
required:true
//姓名非空
type:'Nunmer',
//年龄最大120
type:'String',
enum:['北京','上海']
//只能是北京、上海人
type:'String',
validate:[validator,err]
//validator是一
个验证函数,err是验证失败的错误信息
&& ####7.2 验证失败
&&& 如果验证失败,则会返回err信息,err是一个对象该对象属性如下
err.errors
//错误集合(对象)
err.errors.color
//错误属性(Schema的color属性)
err.errors.color.message
//错误属性信息
err.errors.path
//错误属性路径
err.errors.type
//错误类型
//错误名称
err.message
//错误消息
&&&一旦验证失败,Model和Entity都将具有和err一样的errors属性
& ###8.Middleware中间件
&& ####8.1 什么是中间件
&&& 中间件是一种控制函数,类似插件,能控制流程中的init、validate、save、
remove方法
&& ####8.2 中间件的分类
&&& #####8.2.1 Serial串行
&&&& 串行使用pre方法,执行下一个方法使用next调用
var schema = new Schema(...);
schema.pre('save',function(next){
//做点什么
&&& #####8.2.2 Parallel并行
&&&& 并行提供更细粒度的操作
var schema = new Schema(...);
schema.pre('save',function(next,done){
//下一个要执行的中间件并行执行
doAsync(done);
&& ####8.3 中间件特点
&&& 一旦定义了中间件,就会在全部中间件执行完后执行其他操作,使用中间件
可以雾化模型,避免异步操作的层层迭代嵌套
&& ####8.4 使用范畴
&&& 1. 复杂的验证
&&& 2. 删除有主外关联的doc
&&& 3. 异步默认
&&& 4. 某个特定动作触发异步任务,例如触发自定义事件和通知
&& 例如,可以用来做自定义错误处理
schema.pre('save',function(next){
var err = new Eerror('some err');
next(err);
entity.save(function(err){
console.log(err.message);
//some err
http://cnodejs.org/topic/504bdd
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:130711次
积分:1550
积分:1550
排名:第14833名
原创:31篇
转载:34篇
评论:32条
(6)(2)(18)(1)(2)(11)(1)(2)(3)(2)(1)(4)(2)(2)(7)(1)NodeJS实战:Express+Mongoose+ejs - 推酷
NodeJS实战:Express+Mongoose+ejs
元宵还没到,先向所有朋友拜一个晚年~~~
文章目录:
1、组件版本号
-- --express
-- --Mongoose
2、初始化项目 firstblood
-- --用 express 自动初始化(推荐)
-- --附:手动初始化 package.json
3、关于 express 的 app.js
4、前端模板 Handlebars Ejs Jade
-- --以 Ejs 模板为例
-- --体验一把: route 路由是如何工作的
5、CSS、JS框架支持
-- --bootstrap2.3.2 + jquery 1.11.1 为例
-- --头部尾部重用
6、增删改查少不了
-- --mongodb 小回顾
-- --node 操作 Mongoose 【挑战:一个后台登陆验证+展示mongodb中现有会员信息的小案例】
-- --增强案例:支持登陆并新增修改会员信息的系统,还得支持 session ~
1、组件版本号:
1.1、node:资料大全
1.2、express:
$ express -V
1.3、Mongoose :
$ npm info mongoose version
//$ npm install mongoose
//注:在Windows下安装 **报错(兼容性错误)** 没事的!
//向坚持在 windows 平台的同学致敬……(唉,我的 mac 本本也只是看看电影,没事!)
mongoose@3.8.24 node_modules\mongoose
├── regexp-clone@0.0.1
├── sliced@0.0.5
├── muri@0.3.1
├── hooks@0.2.1
├── mpath@0.1.1
├── mpromise@0.4.3
├── ms@0.1.0
├── mquery@0.8.0 (debug@0.7.4)
└── mongodb@1.4.31 (readable-stream@1.0.33, kerberos@0.0.9, 9, bson@0.2.19)
再次重申: 在 Windows 下安装Mongoose 报错(兼容性错误) 没事的! 没事的!!!
2、初始化项目 firstblood
2.1、用 express 自动初始化(推荐)
1、先全局安装 express:(来自于淘宝国内镜像)
以 3.2.2 为例:
$ npm install -g express@3.2.2 --registry=https://registry.npm.taobao.org
关于 4.0 呢,中间件全被独立出来,网上 download 下来的代码大都是3.x,可能会出错……
建议用3.x。教程也多,一搜一大堆容易解决不常见的坑。
2、创建项目:
快速熟悉下 express 的指令:
Usage: express [options]
-h, --help
输出帮助信息
-V, --version
输出版本号
添加 ejs 模板引擎支持 (默认为jade)
-H, --hogan
添加 hogan.js模板引擎支持
样式 &引擎& 支持 (less|stylus) (默认为css)
-f, --force
强制在非空目录执行
开始安装:
//-e 即支持 ejs; 你喜欢 **ejs** 还是 **jade** ?
$ express firstblood -e
express firstblood -e
create : firstblood
create : firstblood/package.json
create : firstblood/app.js
create : firstblood/public
create : firstblood/routes
create : firstblood/routes/index.js
create : firstblood/routes/user.js
create : firstblood/views
create : firstblood/views/index.ejs
create : firstblood/public/javascripts
create : firstblood/public/images
create : firstblood/public/stylesheets
create : firstblood/public/stylesheets/style.css
install dependencies:
$ cd firstblood && npm install
run the app:
$ node app
//安装组件
$ cd firstblood && npm install
ejs@2.3.1 node_modules\ejs
express@3.2.2 node_modules\express
├── methods@0.0.1
├── fresh@0.1.0
├── cookie-signature@1.0.1
├── range-parser@0.0.4
├── qs@0.6.3
├── buffer-crc32@0.2.1
├── cookie@0.0.5
├── commander@0.6.1
├── mkdirp@0.3.4
├── debug@2.1.1 (ms@0.6.2)
├── send@0.1.0 (mime@1.2.6)
└── connect@2.7.8 (pause@0.0.1, bytes@0.2.0, formidable@1.0.1
这时候 可以启动 node app.js 项目,可以浏览
按 Ctrl + c 结束;
每次代码改动都需要重启 node!不过安装 npm install supervisor 后可以偷懒;它会在你每次修改完代码后自动重启。 神器哦!
3、安装 mongoose
package.json 文件自动更新 dependencies 字段:
npm install mongoose --save
2.2、附:手动初始化 package.json
$ mkdir firstblood && cd firstblood
$ npm init
依次填写: name、version、description、entry point(入口index.js或app.js)、test command(启动指令 node index.js)、git repository(git库)、keywords、author、license(ISC)…… 大胆随便填写,最后 输入 yes 生成 package.json 文件。
接下来安装 mongoose,express,修改 package.json
&dependencies&: {
&mongoose&: &^3.8.24&,
&express&: &3.x&
然后在 当前目录下执行 npm install 安装组件
3、关于 express的 app.js
* Module dependencies. 依赖的模块(处理路由,业务逻辑)
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path');
//实例化 express 并赋值app变量
var app = express();
// all environments 依赖的环境(配置参数)
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
//bodyParser 改成 urlencoded 可以忽略一些 Node窗口里的警告
app.use(express.urlencoded());
//app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only 开发模式(检查错误)
if ('development' == app.get('env')) {
app.use(express.errorHandler());
// 路由解析
app.get('/', routes.index);
app.get('/users', user.list);
// 创建一个http server 启动端口
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
4、前端模板 Handlebars Ejs Jade
关于这个话题移步:
楼主总结: 项目个人秀当然是 jade、商业化的肯定是 Ejs、Handlebars; 楼主喜欢后者……
4.1、以 Ejs 模板为例
让ejs模板文件 支持 html 格式:a:修改app.js
//让Ejs支持 html
app.engine('.html', ejs.__express);
app.set('view engine', 'html');
//app.set('view engine', 'ejs');
b:引入 ejs 模块
//手动添加 ejs 以便支持 .html
ejs = require('ejs');
c:修改 /views 目录下的入口文件后缀为 index.html重启app即可
4.2、体验一把: route 路由是如何工作的
1、在app.js文件中 找到 路由解析部分;添加
app.get('/lu-you-qing-qiu', routes.luyou);
它负责处理你的请求 &/lu-you-qing-qiu&
2、找到: /routes/index.js 文件;添加
exports.luyou = function(req, res){
res.render('lu-you-ye-mian', { title: '“路由”是长这样的!' });
找一个名为 &lu-you-ye-mian.html& (注:上面已经把ejs改成html了哦)去渲染
关于模块化写法,请移步这里:NodeJS 菜鸟入门
3、渲染页面;在 /views/ 目录增加 lu-you-ye-mian.html :
&!DOCTYPE html&
&title&&%= title %&&/title&
&link rel='stylesheet' href='/stylesheets/style.css' /&
&h1&&%= title %&&/h1&
愉快的启动app.js吧!
5、CSS、JS框架支持
1、将 bootstrap 文件夹中的 /css/目录下的所有文件 复制到 /public/stylesheets/
2、将 /js/目录下的所有文件加上再下载一个 jquery 复制到 /public/javascripts/
3、将 /img/ 目录下所有文件复制到 /public/images/
5.2、头部尾部重用
新建 header.html :
&!DOCTYPE html&
&html lang=&en&&
&meta charset=&utf-8&&
&title&&%= title %&&/title&
&!-- Bootstrap --&
&link href=&/stylesheets/bootstrap.min.css& rel=&stylesheet& media=&screen&&
&!-- &link href=&css/bootstrap-responsive.min.css& rel=&stylesheet& media=&screen&& --&
&body screen_capture_injected=&true&&
新建 footer.html :
&script src=&/javascripts/jquery-1.11.1.min.js&&&/script&
&script src=&/javascripts/bootstrap.min.js&&&/script&
那么 index.html 可以改成这样:
&% include header.html %&
&h1&&%= title %&&/h1&
&p&Welcome to &%= title %&&/p&
&% include footer.html %&
6、增删改查少不了
mongodb 安装、启动、常见指令……移步这里Mongodb For Windows
6.1、mongodb 小回顾
接下来为 firstblood 项目创建一点数据 (mongodb 版本号:2.6.6)
& use firstblood
switched to db firstblood
& var listArr = [];for(i=0;i&5;i++){listArr.push({&user&:&test&+i,&password&:&sa
&+i,&age&:i})}
& db.admins.insert(listArr)
BulkWriteResult({
&writeErrors& : [ ],
&writeConcernErrors& : [ ],
&nInserted& : 5,
&nUpserted& : 0,
&nMatched& : 0,
&nModified& : 0,
&nRemoved& : 0,
&upserted& : [ ]
& db.admins.find()
{ &_id& : ObjectId(&54f3f267c0d7f6&), &user& : &test0&, &password& : &
sa0&, &age& : 0 }
{ &_id& : ObjectId(&54f3f267c0d7f7&), &user& : &test1&, &password& : &
sa1&, &age& : 1 }
{ &_id& : ObjectId(&54f3f267c0d7f8&), &user& : &test2&, &password& : &
sa2&, &age& : 2 }
{ &_id& : ObjectId(&54f3f267c0d7f9&), &user& : &test3&, &password& : &
sa3&, &age& : 3 }
{ &_id& : ObjectId(&54f3f267c0d7fa&), &user& : &test4&, &password& : &
sa4&, &age& : 4 }
OK 成功了,暂且多多回顾下其他指令吧
6.2、node 操作 Mongoose 【挑战:一个后台登陆验证+展示mongodb中现有会员信息的小案例】
1、新建目录: mkdir db ;添加数据集合的结构 firstblood_schema.js
// 链接 firstblood 集合
var mongoose = require('mongoose');
var db = mongoose.createConnection('mongodb://127.0.0.1:27017/firstblood');
// 链接错误
db.on('error', function(error) {
console.log(error);
// Schema 结构
var Schema = mongoose.S
var userlistScheMa = new Schema({
: {type : String},
password : {type : String},
: {type : String},
: {type : Date, default: Date.now},
: {type : Number}
// 关联 firstblood -& admins 表
exports.userlist = db.model('admins', userlistScheMa);
exports.db =
关于 Schema 、Model 、Entity 以及 Mongoose 其他APi参考,可以移步这里:
2、在 /routes/ 目录,修改 index.js (当然也可以新建一个文件)
* GET home page.
var firstblood = require('./../db/firstblood_schema.js');
exports.index = function (req, res){
res.render('index', {
title: 'Express',
exports.luyou = function(req, res){
res.render('lu-you-ye-mian', { title: '“路由”是长这样的!' });
exports.login = function (req, res){
res.render('login', {
title: 'login'
/* home */
exports.home = function(req, res) {
var query = {user: req.body.user, password: req.body.password};
firstblood.userlist.count(query, function(err, doc){
if (doc==1) {
var findResult = firstblood.userlist.find(function(error, result){
if (error) {
res.send(error);
res.render('home', {
title : '后台',
status: doc,
username : query.user,
adminlist : result,
date : new Date()
res.render('home', {
title : '后台',
status: doc,
//res.redirect('/');
4、在 app.js 中添加模块依赖(如果新建路由模块的话)和路由:
// 路由解析
// firstblood 项目路由
app.get('/login',routes.login);//增加
app.post('/home',routes.home);//提交
5、在 /views/ 目录,添加 login.html
&% include header.html %&
&div class=&container-fluid&&
&div class=&row-fluid&&
&form class=&span12& action=&home& method=&post&&
&fieldset&
&legend&请输入&/legend&
&span&用户名:&/span&
&input id=&user& name=&user& type=&text&&
&span&密码:&/span&
&input id=&password& name=&password& type=&password&&
&p&&input type=&submit& value=&登陆& class=&btn btn-danger&&&/p&
&/fieldset&
&% include footer.html %&
再添加 home.html
&% include header.html %&
&div class=&container-fluid&&
&div class=&row-fluid&&
&h1&后台管理&/h1&
&% if (status) { %&
&p class=&lead&&欢迎您: &%=username%&&/p&
&p class=&label label-info&&登陆时间: &%=date%&&/p&
&h3&管理员列表&/h3&
&% if (adminlist.length) { %&
&table class=&table table-hover span12&&
&th&#&/th&
&th&用户名&/th&
&th&密码&/th&
&th&年龄&/th&
&% adminlist.forEach(function(data){ %&
&td&&%= data.id %&&/td&
&td&&%= data.user %&&/td&
&td&&%= data.password %&&/td&
&td&&%= data.age %&&/td&
&% } else {%&
&strong&登录失败 &a href=&/&&回首页&/a&&/strong&
&% include footer.html %&
此时启动 app 打开
尝试登陆(用户名密码自然在上文哦~)
小练习:获取 Express 中 HTTP 请求参数:query、body、params
放个小图:
案例小结:以上数据库操作 CURD 只是用到了 Retrieve ,其实API大同小异
6.3、增强案例:支持登陆并新增修改会员信息的系统,还得支持 session ~
By Christopher Buecheler
已发表评论数()
&&登&&&录&&
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见}

我要回帖

更多关于 express4 中间件理解 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信