node 学习之路(二)—— Node.js 连接 MongoDB
前言
之前对于 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,做点有意思的内容。
参考
写这些代码也许就一两个小时的事,写一篇大家好接受的文章需要几天的酝酿,如果文章对您有帮助请我喝杯咖啡吧!
