node学习之路(二)—— Node.js 连接 MongoDB

文章来源:小青年原创
发布时间:2017-4-12
关键词:node,mongodb
转载需标注本文原始地址: http://zhaomenghuan.github.io...

前言

之前对于node的学习,一直只是停留在一种帮前端打辅助的层面,没有深入去研究,是时候需要改变一下了,近来找工作诸多不顺心(找个两情相悦的真不容易啊~),多数对前端有后端语言经验和工作年限有要求,对于我这个应届生真心不是一般的尴尬,所以先继续深入学习一下node咯,本文主要记录一下学习MongoDB数据库相关的内容(属于比较流水账的文章),弥补一下自己的知识空白。这两天收到两个offer心情还是不错的,就是有点难抉择。

mongodb的安装

什么是MongoDB ?

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

官网:https://www.mongodb.com/

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...

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,做点有意思的内容。

参考


匠心博客
看似寻常最奇崛,成如容易却艰辛。始终保持一颗匠心去铸造去创造。

看似寻常最奇崛,成如容易却艰辛。

4.6k 声望
1.5k 粉丝
0 条评论
推荐阅读
基于沙盒技术的企业移动应用安全平台设计
移动互联网的飞速发展, 改变了企业传统的业务模式, 提高了工作效率. 但同时也给企业的数据安全带来了巨大的挑战, 我们面对各种攻击的可能性会大 大增加, 面临潜在的风险:

匠心8阅读 5.4k

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木60阅读 5.9k评论 16

从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木39阅读 7k评论 6

从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...

乌柏木32阅读 6k评论 9

从零搭建 Node.js 企业级 Web 服务器(五):数据库访问
回顾 从零搭建 Node.js 企业级 Web 服务器(一):接口与分层,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,控制层与服务层实现了业务处理过程,模型层定义了业务实体并以 对象-关系...

乌柏木32阅读 4.5k评论 9

从零搭建 Node.js 企业级 Web 服务器(十三):断点调试与性能分析
Node.js 官方提供了断点调试机制,出于安全性考虑默认为关闭状态,可以通过 node 参数 --inspect 或 --inspect-brk 开启,配合 IDE 能够非常方便地调试代码,本章就上一章已完成的项目 licg9999/nodejs-server-ex...

乌柏木29阅读 3.8k评论 9

从零搭建 Node.js 企业级 Web 服务器(八):网络安全
计算机网络依据 TCP/IP 协议栈分为了物理层、网络层、传输层、应用层,通常基础设施供应商会解决好前三层的网络安全问题,需要开发者自行解决应用层的网络安全问题,本章将着重表述应用层常见的网络安全问题及处...

乌柏木31阅读 5.7k评论 1

看似寻常最奇崛,成如容易却艰辛。

4.6k 声望
1.5k 粉丝
宣传栏