node.js数据库篇——Mongoose ODM

介绍mongoose

几乎所有的语言都有原生数据库连接驱动,这个我们上一回已经了解了,比如java的jdbc,mysql-connector,但是实际的开发中为了追求效率都不会使用原生的连接方式这么简单,至少我们也应该封装一个数据库连接文件,不应该每次操作都连接吧。为此,ORM,ODM诞生了,他们简化了数据库操作,将操作打包成简单的方法,并提供了数据的验证规则,安全保障等重要特性。

什么是ORM?

Object Relational Mapping缩写,是对象关系映射,面向对象语言的web开发中重要概念,产品上比如微软的ADO.NET的EntityFramework框架就是提供给ASP.NET开发的关系映射工具,还有笔者之前J2EE开发中SSH框架里的hibernate也是ORM产品,其实说白了就是将面向对象语言中的类(POJO类,那种只有属性和get,set的类)匹配到数据库的表,将实体化后的POJO对象匹配到数据库的一行数据,这样开发者只需要通过get,set对象里的属性,然后save,update一下,像hibernate这样的框架就自动使之对应到了数据库中的具体行,那么数据库就被修改了!这实现了强大的解耦合(开发语言中无需出现SQL语句),使开发者不必去做数据库管理员的事情(甚至不需要知道数据库语言),而专注于代码开发。ORM最大的缺点就是性能远远落后于原生SQL语句,因为像hibernate做的事情实际上就是封装了将对象映射为数据库的SQL语句罢了,永远是逃不过SQL语句操作数据库的。

什么是Mini ORM?

笔者接触mini orm是2015年在为自己创业公司开发ASP.NET平台接触到的,当时使用的产品是Petapoco。Mini orm的出现主要是弥补了ORM低性能的问题,可以理解为精简版的ORM,去除了一些复杂的映射方法,保留了基本的数据库操作方法,并且要求一些复杂的连接语句需要自己手动写SQL,也就是说开发时用基本方法+手动SQL混合式写法,这种ORM对开发者的要求要更高一些,但相比纯SQL还是要简单方便不少,可以说既保留了ORM的功能,同时提高了性能,介于SQL和ORM之间。

什么是ODM?

额,我也是第一次听说这个名词,Object Document Mapper的缩写,以前我只知道ORM,这里我探索了StackOverflow:

以上是别人询问ORM和ODM的区别的采纳回答,大意是:

mysql是关系型数据库,所以你需要用ORM工具将代码中的对象映射为数据库的数据

工具有:hibernate,entity framework,dapper等等

mongodb是文档类数据库,你需要用ODM来将你的代码中的对象翻译为数据库的数据。

mandango就是一个ODM工具

至于这个mandango ODM我看了下github官页说是专为php连接mongodb提供的ODM工具,就对应于node.js下的mongoose了。

什么是mongoose?

相比于原生的mongodb驱动器,mongoose做的第一件简化的事情就是假定了网站使用的是一个数据库,这在mysql中也是很常见的,我们一般一个网站只用一个库!这样整个应用只需要一次连接,处处可用,不必每次都去写连接方法!

然后,使用Mongoose无需担心数据库是否连接上了,他是先把数据库操作指令缓存起来,这就很像那些ORM产品一样,最后一次提交才算数,然后等到提交的时候一次连接数据库,将指令写入数据库。减少了连接次数,提高性能,简化操作验证。这样我们无需监听每一次的connection回掉函数了。

简单测试

package.json

{
"name":"mongoose-test",
"version":"0.0.1",
"description":"a mongoose example",
"dependencies":{
"mongoose":"latest"
}
}

查询数据

//引入mongoose模块
mongoose= require("mongoose"); //连接数据库,需要选择一个固定的库,之后不必再有连接操作
mongoose.connect('mongodb://localhost/test'); //定义模型样板
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId; var dataSchema = new Schema({
email:String,
password:String
}); //生成对象
//第一个参数就是集合名
var User = mongoose.model('User',dataSchema); var name = {email:'devil'}; //根据name字段查询
User.find(name,function(err,data){
console.log(data);
console.log("\n")
}); var password = {password:'123456'}; //根据password字段查询
User.find(password,function(err,data){
console.log(data);
console.log("\n")
});

本次查询的数据就是上一章中构建的登录注册模块所使用的数据库集合User,第一次是查询email为“devil”的数据,第二次是查询密码为“123456”的数据。

新增数据

//引入mongoose模块
mongoose= require("mongoose"); //连接数据库,需要选择一个固定的库,之后不必再有连接操作
mongoose.connect('mongodb://localhost/test'); //定义模型样板
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId; var dataSchema = new Schema({
email:String,
password:String
}); //生成对象
//第一个参数就是集合名
var User = mongoose.model('User',dataSchema); var save = {email:"devilyouwei@foxmail.com",password:"zzzz"};
var user = new User(save);//生成新对象,就是对应数据集合中一条新数据
//保存这个新对象,就是插入操作
user.save(function(err){
console.log("already saved");
})

本次操作通过模型的save方法存储了一行数据

更新操作

//引入mongoose模块
mongoose= require("mongoose"); //连接数据库,需要选择一个固定的库,之后不必再有连接操作
mongoose.connect('mongodb://localhost/test'); //定义模型样板
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId; var dataSchema = new Schema({
email:String,
password:String
}); //生成对象
//第一个参数就是集合名
var User = mongoose.model('User',dataSchema); User.update({email:"devil"},{password:"hello"},function(err){
console.log("password already changed");
})

本次操作将email为“devil”的用户,密码修改为“hello”。

删除操作

//引入mongoose模块
mongoose= require("mongoose"); //连接数据库,需要选择一个固定的库,之后不必再有连接操作
mongoose.connect('mongodb://localhost/test'); //定义模型样板
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId; var dataSchema = new Schema({
email:String,
password:String
}); //生成对象
//第一个参数就是集合名
var User = mongoose.model('User',dataSchema); User.remove({email:"devilyouwei@gmail.com"},function(err){
console.log("devilyouwei@gmail.com already removed");
})

这里我们删除email为“devilyouwei@gmail.com”的数据

解析套路

使用mongoose对数据库进行增删改查的基本套路是:

  • require mongoose模块进来,返回mongoose对象
  • 使用mongoose对象connect进行连接操作,参数为连接套接字默认是:mongodb://localhost/数据库
  • 定义模型样本——schema
  • 根据schema获得对应集合的model,这一步很关键,获得了模型
  • 使用find,remove,save,update对数据库进行基本操作

注意1

注:其中的save方法需要单独解释,我们发现,除了save其他三个没有new Model()操作,也就是不需要生成对象,使用的是静态方法(java中称类方法),比如find:

//生成对象
//第一个参数就是集合名
var User = mongoose.model('User',dataSchema); var name = {email:'devil'}; //根据name字段查询
User.find(name,function(err,data){
console.log(data);
console.log("\n")
});

因为他们(find,remove,update)都是对集合中已经有的数据进行改删查操作,唯独,save是新增操作,必须生成新的对象,故而,save方法是基于新对象下的方法,需要new对象这一步操作:

var save = {email:"devilyouwei@foxmail.com",password:"zzzz"};
var user = new User(save); //重点:生成新对象,就是对应数据集合中一条新数据 //保存这个新对象,就是插入操作
user.save(function(err){
console.log("already saved");
})

注意到上述代码使用了new 模型这种骚操作,并设置的对应属性,这有点像java hibernate下的new对象然后使用set方法,或者直接构造方法传入数据,最后save一下就保存到数据库的操作,ODM和ORM的基本操作十分类似,可以说ODM是专为mongo这样的数据库而生的“特殊ORM”。

注意2

关于schema是个什么?

记住,他并不是模型,要理解schema,可以把它想象成模型的原型(js中叫做prototype),就是model的model(模型的模板),这个schema应当和数据库集合的属性一一对应,集合(表)中有name,那么schema在规定的时候就要有name,否则回误以为是新的集合或者报错。schema用于描述模型的样子以及模型是如何工作的,数据库的操作是发生在模型上的而不是schema上的。

注意3

关于model与数据库集合的对应关系。

首先要获得model,需要通过mongoose.model方法,并且传入集合名,schema。例如:

var dataSchema = new Schema({
email:String,
password:String
}); var User = mongoose.model('User',dataSchema);

User就是一个模型,model方法传入第一个是模型名称,如果model方法没有第三个参数,那么默认第一个参数与数据库集合名对应,注意,默认指定会全部被转换为小写+复数形式,比如这里是User,数据库中的集合叫做users!

注意4

设定默认值,防止空字符串

var dataSchema = new Schema({
email:{type:String,default:"example@gmail.com"},
password:{type:String,default:"123456"}
});

更多常用操作方法

SQL语句丰富多彩,有很多关键词,where,limit,like等等。我以为mongodb不是关系数据库可能不存在或者不太一样,事实上mongoose也有这些关键词,并且是使用类似Thinkphp那样的链式操作。

使用链式操作查询数据

//引入mongoose模块
mongoose= require("mongoose"); //连接数据库,需要选择一个固定的库,之后不必再有连接操作
mongoose.connect('mongodb://localhost/test'); //定义模型样板
var Schema = mongoose.Schema; var userSchema = new Schema({
email:String,
password:String
}); //生成对象
//第一个参数就是集合名
var User = mongoose.model('User',userSchema); User.where('email').eq('devil').exec(function(err,data){
console.log(data);
});

前面的步骤都一样,只是利用了链式操作,把条件依次链接起来,最终使用exec执行整个链。

注意上述代码where和eq组合可以只用find代替:

var User = mongoose.model('User',userSchema);

User.find({email:"devil"},function(err,data){
console.log(data);
}

这段链更加简单,只需要一个find即可

一些常用的链式方法

链式操作的方法名和SQL语言的关键词很相似,基本就是同名同义了

大于小于

var data = User.where('email').gt(1).find(function(err,data){
console.log(data);
})

gt大于,lt小于,eq等于,neq不等于

注意:使用find,exec的效果测试下来效果一样

Like语句

var data = User.where('email').regex(/mail/).find(function(err,data){
console.log(data);
})

在mongoose中并没有找到Like关键词,要模糊查询需要用到正则表达式。regex方法里面可以输入正则表达式。

以上代码用于查找email中带有“mail”字样的行。

count计数

User.find({'email':/mail/}).count(function(err,data){
console.log(data);
})

统计带有“mail”的email的行数,在count中传入回掉函数即可

limit限制

User.find().limit(1).exec(function(err,data){
console.log(data);
})

由于limit必须是基于已经查询好的数据行中限制行数,所以必须在find之后,而limit本身不能传入回调函数,故而可以在最后使用exec执行,exec代表最终执行之前所有的链式方法。否则也没有别的办法取得链式之后想要的数据了。

注:对于那些(比如上述limit)不能提供回调函数,那么直到调用exec才会执行

select选择字段

User.find({email:"devil"}).select("email").exec(function(err,data){
console.log(data);
})

以上代码代表只看email字段,并且select也必须在find之后执行。

sort排序

首先搞清楚SQL中,asc升序,desc降序

//desc
User.find().sort("-email").exec(function(err,data){
console.log(data);
}) //asc
User.find().sort("email").exec(function(err,data){
console.log(data);
})

上面是按照email排序,前面加了负号就是降序,不加负号就是升序。

skip跳过就不说了。

总结:find是找到数据,select,limit,sort,skip等都是筛选操作,都必须在find之后执行,否则要报找不到func错误!

另外select,limit,sort,skip并不能传入回调函数,所以最终获取数据都必须依靠最后一次exec传入回调函数获取!

将js进行到底:node学习9的更多相关文章

  1. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  2. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  3. Node.js环境搭建和学习(windwos环境)

    Node.js环境搭建和学习 一.环境搭建 1.下载安装文件 下载地址http://nodejs-org.qiniudn.com/下载Node.js环境安装包,根据操作系统下载对应的安装包 下载地址 ...

  4. node 学习笔记 - Modules 模块加载系统 (1)

    本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html 用了这么久的 require,但却没有系统的学习过 n ...

  5. [学姿势]实验室搬砖+node学习

    这周开始进行收尾工作,我当然没有进行核心技术的开发,主要负责的是对web端进行展示上的修修补补,主要包括添加VLC播放器.rtsp视频流以及一些js细节. 1.VLC 全称为Video Lan Cli ...

  6. 2015第40周二Node学习

    node历史 今天看cnode开源项目用了io.js,在查这个项目时发现这篇文章node历史,node.js和io.js关系谈到Node.js的由来,不可避免要聊到它的创始人Ryan Dahl.在20 ...

  7. 2015第40周一Node学习

    node学习尝试 早上看了张丹大牛博客文章nodeJS学习路线图和node从零入门系列,感觉获益匪浅,尝试了里面几项内容,对node有了更深入的认识. npm npm是一个node包管理和分发工具,已 ...

  8. Node学习——开篇

    前言:自从下决心转学前端以来,我的专业课java基本荒废了,所以对于后台开发的逻辑也已基本忘干净了.但是作为一名准前端程序猿,我认为还是有必要了解后端开发的,虽不必深入学习,但是能够了解项目从前端到后 ...

  9. node 学习资料

    Node 学习资料: 资料名称 网址 Node.js 中文API文档 http://nodejs.cn/api/ Node 菜鸟教程 http://www.runoob.com/nodejs/node ...

  10. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

随机推荐

  1. 垃圾windows10更新遇到的问题

    缘由 1.win10现在必须更新,不更新不给你用,关闭自动更新的方法都失效了,如果有人知道有效的方法还请私信指教一下.. 一个延迟几天的笨方法:当出现更新并关机或更新并重启时,把电源键设置成关机. 就 ...

  2. JKFZ%你赛炸裂祭

    Md爆40了身败名裂 上来就刚T1是什么习惯?居然不看T2导致明明能刚出正解却止步40 , T3找到原题看懂题解后却不敢交+难码 , 最近怕不是做毒瘤%你赛多了总以为T1能刚到点分 md最近怕不是炸了 ...

  3. 注册服务和发现服务 Eureka

    来自蚂蚁课堂: 注册服务和发现服务 1.原理如图: 注册中心负载均衡: 实践 注册中心 集群:

  4. 新年在家学java之基础篇-高级类的特性

    继承 extends 子类的共性代码都是继承自父类的,每个子类只要写自己特有的代码 class 子类 extends 父类 继承提高了代码的复用性,提供了多态的前提,但是不要为了某个功能去继承 子类不 ...

  5. LeetCode No.148,149,150

    No.148 SortList 排序链表 题目 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 输入: 4->2->1->3 输出: 1->2 ...

  6. Uncaught TypeError: Cannot read property 'querySelector' of null

    报错. 解决办法:把报错部分的js放到body后面

  7. Super Mario HDU - 4417 (主席树询问区间比k小的个数)

    Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory ...

  8. 【更新中】Hotspot tracer

    Hotspot Follower 闲着没事,打算做一个爬取社会热点的项目,首先通过微信搜狗进行分析. 代码基于PYTHON import requests import json def page(s ...

  9. LiauidCrystal

    1.begin()函数语法: lcd.begin(cols,rows) cols:列数: rows:行数: 2.print()函数,语法: lcd.print(data) lcd.print(data ...

  10. 103)PHP,递归读取目录内容

    知识点总结: 打开某个目录 依次读取目录内文件 如果某个文件为目录 递归对该目录采用打开,读取,若还是目录,继续判断,读取 递归点: 如果子文件为目录,则递归 出口: 如果目录中不存在子目录,则不需要 ...