node学习之路(二)—— Node.js 连接 MongoDB
文章来源:小青年原创
发布时间:2017-4-12
关键词:node,mongodb
转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20170412
前言
之前对于node的学习,一直只是停留在一种帮前端打辅助的层面,没有深入去研究,是时候需要改变一下了,近来找工作诸多不顺心(找个两情相悦的真不容易啊~),多数对前端有后端语言经验和工作年限有要求,对于我这个应届生真心不是一般的尴尬,所以先继续深入学习一下node咯,本文主要记录一下学习MongoDB数据库相关的内容(属于比较流水账的文章),弥补一下自己的知识空白。这两天收到两个offer心情还是不错的,就是有点难抉择。
mongodb的安装
什么是MongoDB ?
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
window下mongodb的安装、启动
由于暂时只有window笔记本,这里只介绍window的安装,在官网上下载zip,这个我装在E盘的mongodb目录下。安装教程及常见问题如下:
安装完成后,我们在E:/mongodb/bin下运行mongod会报错:
-bash: mongod: command not found
这是因为我们配置环境变量,如果不想配置我们可以先使用./mongod
代替,如果出现下图结果则说明安装成功。
为了启动mongodb方便,还是将mongod.exe路径加入环境变量,电脑->属性->高级系统设置->环境变量,在path里加入路径:
我们需要给数据库指定存放目录,在E:/mongodb文件夹中创建一个 data 文件夹,再在 data 文件夹中创建 db 文件夹,在命令行执行:
mongod --dbpath E:/mongodb/data/db
其中 --dbpath是指定数据库存放目录,这里要注意有两个 "-"
浏览器打开http://localhost:27017/
,我们会看到:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
至此我们已经成功启动mongodb。
MongoDB安装为Windows服务
我们在E:/mongodb/data文件夹下再建立一个log文件夹,文件夹下新建一个mongodb.log文件,然后在命令行执行:
sc create MongoDB binPath= "E:\mongodb\bin\mongod.exe --service --dbpath E:\mongodb\data\db --logpath=E:\mongodb\data\log\mongodb.log --logappend"
然后我们可以通过net start MongoDB启动MongoDB。
我们可能需要用到的三个命令:
- 启动MongoDB:net start MongoDB
- 停止MongoDB:net stop MongoDB
- 删除MongoDB:sc delete MongoDB
需要特别说明的是,我们需要在管理员模式下输入命令,window+x可以打开管理员命令行。window+R运行打开服务的命令:services.msc,可以打开服务设置界面查看服务相关内容。
mongodb初试
安装可视化工具robomongodb
在开始操作数据库之前,向大家推荐一个连接mongo的客户端可视化工具 robomongodb,它是跨平台的工具,安装后建立连接打开界面是这个样子:
接下来我们的数据操作就可以在这里查看。
MongoDB 概念解析
不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下表将帮助你更容易理解Mongo中的一些概念:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
下表列出了 RDBMS 与 MongoDB 对应的术语:
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键 (MongoDB 提供了 key 为 _id ) |
数据库服务和客户端的区别:
RDBMS | MongoDB |
---|---|
Mysqld/Oracle | mongod |
mysql/sqlplus | mongo |
数据库
一个mongodb中可以建立多个数据库。MongoDB的默认数据库为"test",该数据库存储在data目录中。MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
数据库通过名字来标识,数据库名可以是满足以下条件的任意UTF-8字符串:
- 不能是空字符串("");
- 不得含有' '(空格)、.、$、/、\和\0 (空宇符);
- 应全部小写;
- 最多64字节。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库:
- admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
- local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
合法的集合名:
- 集合名不能是空字符串""。
- 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
- 集合名不能以"system."开头,这是为系统集合保留的前缀。
- 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
文档
文档是一组键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。文档中的键/值对是有序的。文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。MongoDB区分类型和大小写。MongoDB的文档不能有重复的键。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
文档键命名规范:
- 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
- 和$有特别的意义,只有在特定环境下才能使用。
- 以下划线"_"开头的键是保留的(不是严格要求的)。
MongoDB 数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位 |
Boolean | 布尔值。用于存储布尔值(真/假) |
Double | 双精度浮点值。用于存储浮点值 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比 |
Arrays | 用于将数组或列表或多个值存储为一个键 |
Timestamp | 时间戳,记录文档修改或添加的具体时间 |
Object | 用于内嵌文档 |
Null | 用于创建空值 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息 |
Object ID | 对象 ID。用于创建文档的 ID |
Binary Data | 二进制数据。用于存储二进制数据 |
Code | 代码类型。用于在文档中存储 JavaScript 代码 |
Regular expression | 正则表达式类型。用于存储正则表达式 |
数据库操作
我们可以通过mongodb提供的命令行工具(mongo.exe)进行数据库操作,也可以通过程序操作,这里我们先使用命令行工具熟悉基本操作,然后再使用node进行程序操作。打开安装目录bin文件夹下的mongo.exe文件:
列出所有的数据库列表 —— show dbs
命令行输入show dbs
,结果如下:
> show dbs
admin 0.000GB
local 0.000GB
显示当前数据库对象或集合 —— db
执行 "db" 命令可以显示当前数据库对象或集合。
> db
test
创建数据库 —— use DATABASE_NAME
MongoDB 创建数据库的语法格式如下:
use DATABASE_NAME
如果数据库不存在,则创建数据库,否则切换到指定数据库。
运行"use"命令,可以连接到一个指定的数据库。
> use local
switched to db local
> db
local
新建一个数据库,要想通过show dbs
展示出来,需要先插入数据。
删除数据库——db.dropDatabase()
MongoDB 删除数据库的语法格式如下:
db.dropDatabase()
删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。
集合操作
创建集合 —— createCollection()
MongoDB 创建集合的语法格式如下:
db.createCollection(name, options)
在命令中, name 是要创建的集合的名称. Options 是一个文件,用于指定配置的集合
参数 | 类型 | 描述 |
---|---|---|
Name | String | 要创建的集合名称 |
Options | Document | (可选)指定有关内存大小和索引选项 |
选项参数是可选的,所以只需要到指定的集合名称。以下是可以使用的选项列表:
参数 | 类型 | 描述 |
---|---|---|
capped | Boolean | (可选)如果为true,则启用封顶集合。封顶集合是固定大小的集合,会自动覆盖最早的条目,当它达到其最大大小。如果指定true,则需要也指定尺寸参数。 |
autoIndexID | Boolean | (可选)如果为true,自动创建索引_id字段的默认值是false。 |
size | number | (可选)指定最大大小字节封顶集合。如果封顶如果是 true,那么你还需要指定这个字段。 |
max | number | (可选)指定封顶集合允许在文件的最大数量。 |
当插入文档,MongoDB 第一检查大小字段封顶集合,然后它会检查最大的字段中。
createCollection() 方法不使用选项的例子如下:
db.createCollection("blogs")
列出当前数据库所有的集合列表 —— show collections
> show collections
blogs
删除集合 —— db.collection.drop()
MongoDB 删除数据库的语法格式如下:
db.COLLECTION_NAME.drop()
如果集合成功删除,drop() 方法将返回 true,否则将返回 false。
文档操作
插入文档 —— db.COLLECTION_NAME.insert(document) 或 db.COLLECTION_NAME.save(document)
> db.blogs.insert({
... "pageId":"20170401",
... "pageUrl":"http://zhaomenghuan.github.io/#!/blog/20170401",
... "title":"Angular系列学习笔记(二)—— 基于gulp构建Angular单页面应用",
... "from":"原创",
... "time":"2017-4-1",
... "keyword":["gulp","angular","angular-ui-router","angular-material"],
... "digest":"构建打包工具之前一直是使用 webpack(歪脖帕克,毕竟尤大推荐的工具),由于公司这边是使用gulp,为了和公司同步,私下还是要学习学习,毕竟懂点万一需要和老大交流也不至于说有啥问题,这篇文章将会以零基础的角度去
写一下基于gulp搭建angular的工程,借这个机会顺便重构一下自己的博客。"
... })
WriteResult({ "nInserted" : 1 })
这里 blogs是集合的名称,如上面的例子中创建。如果集合在数据库中不存在,那么MongoDB 将创建此集合,然后把它插入文档。插入文档中,如果我们不指定_id参数,然后MongoDB 本文档分配一个独特的ObjectId。_id 是12个字节的十六进制数,唯一一个集合中的每个文档。 12个字节被划分如下:
_id: ObjectId(4 bytes timestamp, 3 bytes machine id, 2 bytes process id, 3 bytes incrementer)
要插入单个查询的多个文档,可以传递一个文件数组作为 insert() 命令的参数。
mongodb insert()和save()的相同点和区别:
若新增的数据中存在主键 ,insert() 会提示错误,而save() 则更改原来的内容为新内容。若新增的数据中没有主键时,会增加一条记录。
如:
已存在数据: {_id : 1, " name " : " n1 " },再次进行插入操作时,
insert({_id : 1, " name " : " n2 " }) 会报主键重复的错误提示;
save({ _id : 1, " name " : " n2 " }) 会把 n1 修改为 n2 。
查询文档 —— db.COLLECTION_NAME.find()
find() 方法将在非结构化的方式显示所有的文件,还有一个 findOne() 法返回一个文件。
> db.blogs.find()
{ "_id" : ObjectId("58ecf1a2b36ebd2cfd5321f6"), "pageId" : "20170401", "pageUrl" : "http://zhaomenghuan.github.io/#!/blog/20170401", "title" : "Angular系列学习笔记(二)—— 基于gulp构建Angular单页面应用", "from" : "
原创", "time" : "2017-4-1", "keyword" : [ "gulp", "angular", "angular-ui-router", "angular-material" ], "digest" : "构建打包工具之前一直是使用 webpack(歪脖帕克,毕竟尤大推荐的工具),由于公司这边是使用gulp,为了和公
司同步,私下还是要学习学习,毕竟懂点万一需要和老大交流也不至于说有啥问题,这篇文章将会以零基础的角度去写一下基于gulp搭建angular的工程,借这个机会顺便重构一下自己的博客。" }
如果需要格式化显示结果,可以使用pretty()方法。
db.COLLECTION_NAME.find().pretty()
RDBMS Where子句和MongoDB等同语句:
要查询文件的一些条件的基础上,可以使用下面的操作:
操作 | 语法 | 例子 | RDBMS 等同 |
---|---|---|---|
等于 | {<key>:<value>} | db.mycol.find({"by":"tutorials yiibai"}).pretty() | where by = 'tutorials yiibai' |
小于 | {<key>:{$lt:<value>}} | db.mycol.find({"likes":{$lt:50}}).pretty() | where likes < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.mycol.find({"likes":{$lte:50}}).pretty() | where likes <= 50 |
大于 | {<key>:{$gt:<value>}} | db.mycol.find({"likes":{$gt:50}}).pretty() | where likes > 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.mycol.find({"likes":{$gte:50}}).pretty() | where likes >= 50 |
不等于 | {<key>:{$ne:<value>}} | db.mycol.find({"likes":{$ne:50}}).pretty() | where likes != 50 |
注:$gt —— greater than;$gte —— greater than equal;$lt —— less than;$lte —— less than equal;$ne —— not equal
AND 条件在MongoDB中用法:
在 find() 方法,如果通过多个键分离',',那么 MongoDB 处理 AND 条件。AND 基本语法如下所示:
db.COLLECTION_NAME.find({key1:value1, key2:value2}).pretty()
OR 条件在MongoDB中用法:
OR条件的基础上要查询文件,需要使用$or关键字。OR 基本语法如下所示:
db.COLLECTION_NAME.find({
$or: [{key1: value1}, {key2:value2}]
}).pretty()
更新文档 —— db.COLLECTION_NAME.update(SELECTIOIN_CRITERIA, UPDATED_DATA) 或 db.COLLECTION_NAME.save(document)
db.COLLECTION_NAME.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的。
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
db.blogs.update({
'pageId':'20170401'
},{
$set:{'pageId':'2017-04-01'}
})
save() 方法通过传入的文档来替换已有文档。语法格式如下:
db.COLLECTION_NAME.save(
<document>,
{
writeConcern: <document>
}
)
参数说明:
- document : 文档数据。
- writeConcern :可选,抛出异常的级别。
删除文档 —— db.COLLECTION_NAME.remove(DELLETION_CRITTERIA)
db.COLLECTION_NAME.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
query :(可选)删除的文档的条件。
justOne : (可选)如果设为 true 或 1,则只删除一个文档。
writeConcern :(可选)抛出异常的级别。
文档排序 —— db.COLLECTION_NAME.find().sort()
在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。
$type 操作符
$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。
MongoDB 中可以使用的类型如下表所示:
类型 | 数字 |
---|---|
Double | 1 |
String | 2 |
Object | 3 |
Array | 4 |
Binary data | 5 |
Undefined | 6 (已废弃) |
Object id | 7 |
Boolean | 8 |
Date | 9 |
Null | 10 |
Regular Expression | 11 |
JavaScript | 13 |
Symbol | 14 |
JavaScript (with scope) | 15 |
32-bit integer | 16 |
Timestamp | 17 |
64-bit integer | 18 |
Min key | 255(Query with -1) |
Max key | 127 |
db.blogs.find({"title" : {$type : 2}})
Limit与Skip方法限制记录 —— db.COLLECTION_NAME.find().limit(NUMBER)
如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
除了limit() 方法,还有一个方法skip() 也接受数字类型的参数,并使用跳过的文档数。skip()方法默认参数为 0 。
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
Node.js 连接 MongoDB
使用 Node.js 来连接 MongoDB,并对数据库进行操作,我们需要先下载MongoDB的node版本的驱动。
官方文档地址:http://mongodb.github.io/node-mongodb-native/
1.下载依赖包:
npm install mongodb --save
2.建立连接
var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/zhaomenghuan';
// Use connect method to connect to the server
MongoClient.connect(DB_CONN_STR, function(err, db) {
console.log("Connected successfully to server");
db.close();
});
与 MySQL 不同的是 MongoDB 会自动创建数据库和集合,所以使用前我们不需要手动去创建。
3.操作数据库
和前面将到的操作类似,下面我们直接给出例子:
var MongoClient = require('mongodb').MongoClient;
var DB_CONN_STR = 'mongodb://localhost:27017/zhaomenghuan';
MongoClient.connect(DB_CONN_STR, function(err, db) {
insertData(db, function (result) {
console.log(result);
db.close();
});
});
function insertData(db, callback) {
var data = {
"pageId":"20160816",
"pageUrl":"http://zhaomenghuan.github.io/#!/blog/20160816",
"title":"JavaScript进阶学习(三)—— 基于html5 File API文件操作",
"from":"原创",
"time":"2016-08-16",
"keyword":["blob","File","FileReader","DataURI","URL"],
"digest":"这段时间一直有朋友在问文件上传下载的事,搜一下论坛发现相关的问题不少,但是不够系统,本着为人民服务的态度本文试着将一些问题整理一下,争取用初学者可以更明确的去处理相关的问题。文件上传是开发中绕不过的一个坎儿,对于很多没有经验的人来说,简直懵逼,目前我所知道的上传方式有下面这几种:传统flash上传、隐藏iframe框上传、表单数据提交、HTML5的新工具——File API。"
};
// 连接到表 blogs
var collection = db.collection('blogs');
collection.insertOne(data, function (err, result) {
if (err) {
console.log('Error:' + err);
return;
}
callback(result);
});
}
对于具体的差异,需要通过查阅API文档进行进一步的学习,API文档见这里:API DOC。
本文介绍了一下mongodb的基本操作,详细的操作更多需要继续学习官方手册,接下来我们结合node,做点有意思的内容。