初学Node.js
接触到MongoDB
数据库,阅读资料中推荐的都是Mongoose
模块,能够更加方便的对数据库进行操做,便开始接触Mongoose
。在学习时碰到许多基础问题,查阅了许多资料理来理解,此篇文章就是以本身的理解,记录下入门的基础知识,以及概括下经常使用的函数以及格式,方便从此查阅。
初学笔记不免有许多不足与错误欢迎指出。html
若是须要在本地测试,须要先安装MongoDB数据库。
在官网下载最新安装包。安装成功后,在命令行下进入MongoDB\bin
目录node
mongod --dbpath D:\MongoDB\data
启动数据库。正则表达式
http://localhost:27017/
在浏览器中访问这地址,访问正常则数据库启动成功。
更详细的说明能够查看《MongoDB的下载、安装与部署》mongodb
npm install mongoose
在已经安装过Node.js的电脑上,进入工做目录输入以上命令便可安装Mongoose模块。数据库
Robomongo
是一款不错的可视化工具,Windows、MacOS、Linux平台都有,界面也简洁。虽然有收费,普通操做免费版足够用。
官网下载npm
在须要使用的js文件中引入模块。api
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/mongodb');
URL以mongodb://
+ [用户名:密码@]
+数据库地址[:端口]
+ 数据库名
。(默认端口27017)
须要对链接情况进行判断,能够用如下代码:数组
db.connection.on("error", function (error) { console.log("数据库链接失败:" + error); }); db.connection.on("open", function () { console.log("数据库链接成功"); }) db.connection.on('disconnected', function () { console.log('数据库链接断开'); })
最常接触到的有三个概念Schema
、Model
、Entity
。按本身理解,Schema
是定义数据库的结构。相似建立表时的数据定义,但比建立数据库能够作更多的定义,只是没办法经过Schema对数据库进行更改。Model
是将Schema定义的结构赋予表名。但可用此名对数据库进行增删查改。Entity
是将Model与具体的数据绑定,能够对具体数据自身进行操做,例如保存数据。浏览器
Schema用来定义数据库文档结构,数据库有什么字段、字段是什么类型、默认值、主键之类的信息。除了定义结构外,还能定义文档的实例方法,静态模型方法,复合索引,中间件等。详情查看mongoose官方文档。
在引入Mongoose模块var mongoose = require('mongoose')
的js文件中进行操做。安全
var blogSchema = new mongoose.Schema({ title: String, comments: [{ body: String, date: Date }], date: { type: Date, default: Date.now }, hidden: Boolean, meta: { votes: Number, favs: Number } })
这样即定义了一个名为blogSchema
的Schema。
如需再添加数据,用add
方法。
blogSchema.add( { author: String, body: String} );
资料中介绍,Shema
不只定义了文档的结构和属性,还能够定义文档的插件、实例方法、静态方法、复合索引文档生命周期钩子,具体还需查看官方文档。
Schema.Type
是Mongoose内部定义的数据类型。基本类型有:String
、Number
、Date
、Boolean
、Array
、Buffer
、Mixed
、ObjectId
。
Mixed
混合数据类型,能够直接定义{}
来使用,如下两种形式等价。
new Schema({mixed: {Schema.Types.Mixed} }); new Schema({mixed: {} });
ObjectId
储存在数据库中的每一个数据都会有默认的主键_id
,默认存储的是ObjectId
。ObjectId
是一个12字节的BSON
类型字符串。按照字节顺序依次表明:
4字节:UNIX时间戳
3字节:表示运行MongoDB的机器
2字节:表示生成此_id的进程
3字节:由一个随机数开始的计数器生成的值
var blogModel = mongoose.model('Blog', blogSchema);
将名为blogSchema
的Schema与Blog
名字绑定,便是存入数据库的名字,但存入数据库中的名字是Blogs
,会自动添加一个s
。
这里将Model命名为blogModel
,须要对Blog
表操做的话,都须要使用变量名blogModel
。
能够绑定具体数据对Model实例化。
var blogEntity = new blogModel({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } })
这里将名为blogModel
的Model实例化。以后咱们能够用blogEntity
名对数据进行保存并执行回调。
blogEntity.save(function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); })
在日常使用SQL语句操做数据库时,取得数据后先组织成SQL语句,而后放入执行语句中执行。这里理解也是相似,取得数据先进行实例化,这一步相似于组织成SQL语句,而后再作具体操做例如上面的Save
操做。但因为Node.js是异步操做,因此返回的数据利用回调函数来进行操做。
知道了以上概念后就能够对数据进行操做了,下面将列出一些经常使用的资料,并附上相应的例子。
全部的参数都是以JSON对象
形式传入。
var doc = ({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } }; blogModel.create(doc, function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
Model#save([options], [options.safe], [options.validateBeforeSave], [fn])
var blogEntity = new blogModel({ title: "Mongoose", author: "L", body: "Documents are instances of out model. Creating them and saving to the database is easy", comments: [{ body: "It's very cool! Thanks a lot!", date: "2014.07.28" }], hidden: false, meta: { votes: 100, favs: 99 } }); blogEntity.save(function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
多条数据插入,将多条数据一次性插入,相对于循环使用create
保存会更加快。
blogModel.insertMany([ {title: "mongoose1", author: "L"}, {title: "mongoose2", author: "L"} ], function(err, docs){ if(err) console.log(err); console.log('保存成功:' + docs); });
conditions
:查询条件;projection
:控制返回的字段;options
:控制选项;callback
:回调函数。
blogModel.find({title: "Mongoose", meta.votes: 100}, {title: 1, author: 1, body: 1}, function(err, docs){ if(err) console.log(err); console.log('查询结果:' + docs); })
查询“title”标题为“Mongoose”,而且“meta”中“votes”字段值为“100”的记录,返回仅返回“title”、“author”、“body”三个字段的数据。
Model.findOne([conditions], [projection], [options], [callback])
conditions
:查询条件;projection
:控制返回的字段;options
:控制选项;callback
:回调函数。
只返回第一个查询记录。
id
:指定_id
的值;projection
:控制返回的字段;options
:控制选项;callback
:回调函数。
conditions
:查询条件;doc
:须要修改的数据,不能修改主键(_id
);options
:控制选项;callback
:回调函数,返回的是受影响的行数。options
有如下选项:
safe (boolean): 默认为true。安全模式。
upsert (boolean): 默认为false。若是不存在则建立新记录。
multi (boolean): 默认为false。是否更新多个查询记录。
runValidators: 若是值为true,执行Validation验证。
setDefaultsOnInsert: 若是upsert选项为true,在新建时插入文档定义的默认值。
strict (boolean): 以strict模式进行更新。
overwrite (boolean): 默认为false。禁用update-only模式,容许覆盖记录。
blogModel.update({title: "Mongoose"}, {author: "L"}, {multi: true}, function(err, docs){ if(err) console.log(err); console.log('更改为功:' + docs); })
以上代码先查询“title”为“Mongoose”的数据,而后将它的“author”修改成“L”,“multi”为true容许更新多条查询记录。
一次更新多条
一次更新一条
Model.findByIdAndUpdate(id, [update], [options], [callback])
id
:指定_id
的值;update
:须要修改的数据;options
控制选项;callback
回调函数。options
有如下选项:
new: bool - 默认为false。返回修改后的数据。
upsert: bool - 默认为false。若是不存在则建立记录。
runValidators: 若是值为true,执行Validation验证。
setDefaultsOnInsert: 若是upsert选项为true,在新建时插入文档定义的默认值。
sort: 若是有多个查询条件,按顺序进行查询更新。
select: 设置数据的返回。
Model.findOneAndUpdate([conditions], [update], [options], [callback])
conditions
:查询条件;update
:须要修改的数据;options
控制选项;callback
回调函数。options
有如下选项:
new: bool - 默认为false。返回修改后的数据。
upsert: bool - 默认为false。若是不存在则建立记录。
fields: {Object|String} - 选择字段。相似.select(fields).findOneAndUpdate()。
maxTimeMS: 查询用时上限。
sort: 若是有多个查询条件,按顺序进行查询更新。
runValidators: 若是值为true,执行Validation验证。
setDefaultsOnInsert: 若是upsert选项为true,在新建时插入文档定义的默认值。
passRawResult: 若是为真,将原始结果做为回调函数第三个参数。
blogModel.remove({author: "L"}, function(err, docs){ if(err) console.log(err); console.log('删除成功:' + docs); })
删除“author”值为“L”的记录。
id
:指定_id
的值;update
:须要修改的数据;options
控制选项;callback
回调函数。options
有如下选项:
sort: 若是有多个查询条件,按顺序进行查询更新。
select: 设置数据的返回。
conditions
:查询条件;update
:须要修改的数据;options
控制选项;callback
回调函数。options
有如下选项:
sort: 若是有多个查询条件,按顺序进行查询更新。
maxTimeMS: 查询用时上限。
select: 设置数据的返回。
在以前的查询说明中仅演示了肯定值的查询,若是遇到更加复杂的状况就须要使用其余一些方法。
详细的文档能够在这儿查找 mongodb查询符。
执行查询,回调函数。
使用find()
、$where
之类查询返回的是Mongoose本身封装的Query对象,使用find()
能够在函数最后接上回调来获取查询到的数据。
使用链式语句时,能够在以后接.exec()
执行查询,并指定回调函数。
blogModel.find({title: "Mongoose", meta.votes: 100}, {title: 1, author: 1, body: 1}).exec(function(err, docs){ if(err) console.log(err); console.log('查询结果:' + docs); })
配合各类查询符能够方便的实现复杂的查询。
好比我须要查询“title”中以“Mongoose”开头,而且“meta”中“votes”的值小余100。而且按“meta”中“votes”的值升序排序。
blogModel.and([ { title: { $regex: "Mongoose.+","$options":"i"}}, { meta.votes: { $lt: 100}} ).sort({ meta.votes: 1} ).exec(function(err, docs){ if(err) console.log(err); console.log('查询结果:' + docs); });
$equals 等于 / $gt 大于 / $gte 大于等于 / $lt 小余 / $lte 小余等于 / $ne 不等于 / $in 在数组中 / $nin 不在数组中
blogModel.find({meta.votes: {$lt: 100}});
查询“meta”中的“votes”字段值小余100的数据。
blogModel.find({title: {$in: ['Mongoose', 'Mongodb', 'Nodejs']}});
查询“title”为“Mongoose”或“Mongodb”或“Nodejs”其中之一的数据。
blogModel.find({ $and: [ {meta.votes: {$gte: 50}}, {meta.votes: {$lt: 100}} ]});
查询“meta”中的“votes”字段值大于等于50到小余100的数据。
blogModel.find({ $nor: [ {meta.votes: 50}, {meta.votes: 100} ]});
查询“meta”中的“votes”字段值不等于50和不等于100的数据。
以上例子也能够写成这样形式,比较清晰,其余类同
blogModel.and([ {meta.votes: {$gte: 50}}, {meta.votes: {$lt: 100}} ]); blogModel.nor([ {meta.votes: 50}, {meta.votes: 100} ]);
$exists 查询的字段值是否存在
blogModel.find({ title: {$exists: true}}); blogModel.where('title').exists(true);
查询存在“title”字段的数据。
$mod 与数据进行取模运算筛选
blogModel.find({ meta.votes: {$mod: [4, 0]}}); blogModel.where('meta.votes').$mod(4, 0);
查找“meta”中的“votes”字段值与4取模后,值为0的数据。
$regex 使用正则表达式查询数据
blogModel.find({ title: { $regex: "Mongoose.+","$options":"i"}});
搜索以“Mongoose”开头的“title”字段,“options”中的“i”表明不区分大小写。$options
参数与其他用法能够查看mongodb文档中 $regex 一节。
$where 支持js表达式查询
blogModel.find({ $where: 'this.comments.length === 10 || this.name.length === 5' }); blogModel.$where(function() { return this.comments.length === 10 || this.name.length === 5; });
Query#all([path], val) 查询数组的自己及超集
blogModel.find( tags: ['nodejs', 'mongoose']);
查询“tags”的字段值同时包含有['nodejs', 'mongoose']的数据。只要值中包含此数组即返回数据,如果只包含数组中的一个则不返回此数据。
Query#elemMatch(path, criteria) 查询数组的交集
blogModel.find( $elemMatch: { tags: 'mongoose', author: 'L'});
查询“tags”为“mongoose”或是“author”为“L”的数据。
Query#size([path], val) 查询指定大小的数组
blogModel.find( tags: { $size: 2}); blogModel.where('tags').size(2);
查询“tags”数组中包含两个元素的数据。
Query#limit(val) 限制查询返回的数量
blogModel.find( tags: 'mongoose').limit(5);
查询“tags”为“mongoose”的数据,只返回前5个查询结果。
Query#skip(val) 跳过前N个查询结果
blogModel.find( tags: 'mongoose').skip(10).limit(5);
查询“tags”为“mongoose”的数据,跳过前10个查询结果,返回从第11个开始的五个查询结果。
作分页时经常使用到这两个,但数据量过大时就会有性能问题。
Query#sort(arg) 对结果按某个指定字段进行排序
1
、asc
为升序,-1
、desc
为降序。能够对一个字段进行排序,也能够是多个。
blogModel.find( tags: 'mongoose').skip(10).limit(5).sort("{ meta.votes: 1}");
查询“tags”为“mongoose”的数据,跳过前10个查询结果,返回从第11个开始的五个查询结果。以后按“votes”进行升序排序。
blogModel.count({ title: 'mongoose'}, function(err, docs){});
统计“title”为“mongoose”数据的数量
Query#select(arg) 选择指定字段
在查询中能够选择指定的查询字段,或者排除指定的字段。+
为包含,-
为排除。
blogModel.select('title body');
只包含“title”、“body”字段。
blogModel.select('-title -body');
排除“title”、“body”字段。