第一章 MongoDB基本原理与快速实战


前言

在数据量暴增的时代,若想用传统的关系型数据库来满足数据高并发读写,海量数据的存储,数据库的扩展和高可用等,则需要增加软硬件的规格,这将大幅提高成本。因此,Nosql数据库这种低成本的分布式数据库成为许多企业的首选。


一、MongoDB是什么?

官网:www.mongodb.com
中文网:www.mongodb.org.cn
MongoDB是一个半结构化的非关系型数据库,由C++语言编写,它对数据的结构没有硬性限制,以BSON(Binary JSON)格式来保存数据,有着分布式的存储结构,能有效解决海量数据的存储与高并发访问效率的问题,为数据存储提供性能佳且扩展性高的解决方案。

MongoDB vs 关系型数据库

Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。原则上 Oracle 和 MySQL 能做的事情,MongoDB 都能做(包括 ACID 事务)。
MongoDB概念与关系型数据库(RDBMS)非常类似:
在这里插入图片描述

  • 数据库(database):最外层的概念,可以理解为逻辑上的名称空间,一个数据库包含多个不同名称的集合。
  • 集合(collection):相当于SQL中的表,一个集合可以存放多个不同的文档。
  • 文档(document):一个文档相当于数据表中的一行,由多个不同的字段组成。
  • 字段(field):文档中的一个属性,等同于列(column)。 索引(index):独立的检索式数据结构,与SQL概念一致。
  • _id:每个文档中都拥有一个唯一的_id字段,相当于SQL中的主键(primary key)。
  • 视图(view):可以看作一种虚拟的(非真实存在的)集合,与SQL中的视图类似。从MongoDB3.4版本开始提供了视图功能,其通过聚合管道技术实现。
  • 聚合操作($lookup):MongoDB用于实现“类似”表连接(tablejoin)的聚合操作符。

尽管这些概念大多与SQL标准定义类似,但MongoDB与传统RDBMS仍然存在不少差异,包括:

  • 半结构化,在一个集合中,文档所拥有的字段并不需要是相同的,而且也不需要对所用的字段进行声明。因此,MongoDB具有很明显的半结构化特点。除了松散的表结构,文档还可以支持多级的嵌套、数组等灵活的数据类型,非常契合面向对象的编程模型。
  • 弱关系,MongoDB没有外键的约束,也没有非常强大的表连接能力。类似的功能需要使用聚合管道技术来弥补。

MongoDB技术优势

MongoDB基于灵活的JSON文档模型,非常适合敏捷式的快速开发。与此同时,其与生俱来的高可用、高水平扩展能力使得它在处理海量、高并发的数据应用时颇具优势。
简单直观:从错综复杂的关系模型到一目了然的对象模型
在这里插入图片描述
快速:最简单快速的开发方式
在这里插入图片描述
灵活:快速响应业务变化
在这里插入图片描述
MongoDB优势:原生的高可用
在这里插入图片描述
MongoDB优势:横向扩展能力
在这里插入图片描述

MongoDB应用场景

从目前阿里云 MongoDB 云数据库上的用户看,MongoDB 的应用已经渗透到各个领域:

  • 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新;
  • 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来;
  • 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能;
  • 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析;
  • 视频直播,使用 MongoDB 存储用户信息、礼物信息等;
  • 大数据应用,使用云数据库MongoDB作为大数据的云存储系统,随时进行数据提取分析,掌握行业动态。|
    国内外知名互联网公司都在使用MongoDB:
    在这里插入图片描述

如何考虑是否选择MongoDB?

没有某个业务场景必须要使用MongoDB才能解决,但使用MongoDB通常能让你以更低的成本解决问题。如果你不清楚当前业务是否适合使用MongoDB,可以通过做几道选择题来辅助决策。
在这里插入图片描述
只要有一项需求满足就可以考虑使用MongoDB,匹配越多,选择MongoDB越合适。


二、快速开始

1.安装启动

环境准备:

# 下载MongoDB
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.14.tgz
tar -zxvf mongodb-linux-x86_64-rhel70-4.4.14.tgz

启动方式1:命令行启动

# 创建dbpath和logpath
mkdir -p /mongodb/data /mongodb/log  
# 进入mongodb目录,启动mongodb服务,也可配置环境变量
bin/mongod --port=27017 --dbpath=/mongodb/data --logpath=/mongodb/log/mongodb.log \
--bind_ip=0.0.0.0 --fork

启动方式2:配置文件启动
编辑/mongodb/conf/mongo.conf文件:

vim /mongodb/conf/mongo.conf
systemLog:
  destination: file
  path: /mongodb/log/mongod.log # log path
  logAppend: true    # 追加日志
storage:
  dbPath: /mongodb/data # data directory
  engine: wiredTiger  # 存储引擎
  journal:            # 是否启用journal日志
    enabled: true
net:
  bindIp: 0.0.0.0
  port: 27017 # port
processManagement: 
  fork: true   # 后台启动
# -f 选项表示将使用配置文件启动mongodb
mongod -f /mongodb/conf/mongo.conf

关闭方式1:

mongod --port=27017 --dbpath=/mongodb/data --shutdown 

关闭方式2:

# 进入mongo shell
use admin
db.shutdownServer()

2.Mongo shell使用

mongo是MongoDB的交互式JavaScript Shell界面,它为系统管理员提供了强大的界面,并为开发人员提供了直接测试数据库查询和操作的方法。
进入mongo shell:

bin/mongo --port=27017 
# 或
bin/mongo localhost:27017

–port:指定端口,默认为27017
–host:连接的主机地址,默认127.0.0.1

mongo shell常用命令

命令说明
show dbs /show databases显示数据库列表
use 数据库名切换数据库,如果不存在创建数据库
db.dropDatabase()删除数据库
show collections / show tables显示当前数据库的集合列表
db.集合名.stats()查看集合详情
db.集合名.drop()删除集合
show users显示当前数据库的用户列表
show roles显示当前数据库的角色列表
show profile显示最近发生的操作
load(“xxx.js”)执行一个JavaScript脚本文件
exit / quit()退出当前shell
help查看mongodb支持哪些命令
db.help()查询当前数据库支持的方法
db.集合名.help()显示集合的帮助信息
db.version()查看数据库版本

数据库操作(示例):

// 查看所有库
show dbs
// 切换到指定数据库,不存在则创建
use test
// 删除当前数据库  
db.dropDatabase()

集合操作(示例):

// 查看集合
show collections
// 创建集合
db.createCollection("test")
// 删除集合
db.emp.drop()

创建集合语法:

db.createCollection(name, options)
字段类型描述
capped布尔(可选)如果为true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。
size数值(可选)为固定集合指定一个最大值(以字节计)。如果 capped 为 true,也需要指定该字段。
max数值(可选)指定固定集合中包含文档的最大数量。

安全认证

创建管理员账号:

// 设置管理员用户名密码需要切换到admin库
use admin  
// 创建管理员 roles为权限
db.createUser({user:"nanmian",pwd:"nanmian",roles:["root"]})
// 查看当前数据库所有用户信息 
show users 
// 显示可设置权限
show roles 
// 显示所有用户
db.system.users.find()

常用权限:

权限名描述
read允许用户读取指定数据库
readWrite允许用户读写指定数据库
dbAdmin允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
dbOwner允许用户在指定数据库中执行任意操作,增、删、改、查等
userAdmin允许用户向system.users集合写入,可以在指定数据库里创建、删除和管理用户
clusterAdmin只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限
readAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限
root只在admin数据库中可用。超级账号,超级权限

重新赋予用户权限

db.grantRolesToUser( "nanmian" , [ 
    { role: "clusterAdmin", db: "admin" } ,
     { role: "userAdminAnyDatabase", db: "admin"},
     { role: "userAdminAnyDatabase", db: "admin"},
     { role: "readWriteAnyDatabase", db: "admin"} 
 ])

删除用户

db.dropUser("nanmian")
// 删除当前数据库所有用户
db.dropAllUser()

创建应用数据库用户

use appdb
db.createUser({user:"appdb",pwd:"nanmian",roles:["dbOwner"]})

注意:默认情况下,MongoDB不会启用鉴权,以鉴权模式启动MongoDB

mongod -f /mongodb/conf/mongo.conf --auth

启用鉴权之后,连接MongoDB的相关操作都需要提供身份认证。

mongo 127.0.0.1:27017 -u nanmian -p nanmian --authenticationDatabase=admin

文档操作

插入

在MongoDB中,最常用的插入语法为insert()和save(),除此之外,3.2版本新增了db.collection.insertOne() 和 db.collection.insertMany()。不过insert()已涵盖这两个指令的功能。

1. insert()
此方法是插入文档最常用的方法,可以插入单笔或多笔文档,若插入的数据主键已经存在,则会抛 DuplicateKeyException 异常,提 示主键重复,不保存当前数据。
(1)语法格式:

db.collection.insert(
  <document or array of doocument>,
  {
     writeConcern: <document>,
     ordered:<boolean>
  }
)

(2)参数说明:

  • document or array of doocument:要被插入的文档或数组,单个文档时如:{doc},数组时如:[{doc1},{doc2}]

  • writeConcern:此为可选参数,表示是否使用写入策略,writeConcern 包含以下字段:

     {w:<>,J:<布尔值>,wtimeout:<数字>}
    

    其中w字段可以是以下几种形式:

    • 整数数字N:表示在反馈操作成功前必须同步到N个副本节点上。
      – 设为1时:表示只有写入主节点才会有反馈,此为默认模式。
      – 设为0时:表示谁也不用,但可能会出现未写入成功应用程序却未收到错误提示的情况
      – 设为大于1的数时:则需要写入此数的节点,但需特别注意的是集群节点数需大于此数,否则可能会报错。
    • majority:必须写入超过大多数节点上才算成功。需注意的是,在副本集中如果有仲裁节点,则可能出现这种情况——即使所有副本数据都已同步,但仍无法满足超过大多数的条件而出现异常。
    • 标签集合:数据需写到该标签的副本节点上,MongoDB才会给出写入成功的回应。

    J字段表示“写”操作是否要记录到日志文件(journal)中,若设置为true,则在服务发生意外时可通过日志恢复数据。

    wtimeout字段表示等待时间的限制,单位为ms,若超过此限制则写入失败,合理设置该字段可以避免写操作无止尽的等待,但只有w的值大于1时,这个属性才会生效。

  • ordered:可选参数,表示插入文档时是否为有序插入,默认为true。若为有序插入时发生错误,MongoDB将不再插入后续的文档,无序插入时则反之。

(3)示例

db.Product.insert(
  [{
  	SysNo:2971,
  	ProductName:"DE-1300 Earbuds",
  	Weight:465,
  	Color:["Red","white"],
  	ProductMode:"Set"
  },
  {
  	SysNo:8622,
  	ProductName:"(Rose Gold) 16GB",
  	Weight:143,
  	Color:["Red","Blue"],
  	ProductMode:""
  }],
  {
     writeConcern: {w:"majority",j:true,wtimeout:5000},
     ordered:false
   }
)
// 写入大多数节点,写入日志,限时5000ms

在插入文档时,如果没有指定数据库,MongoDB则会自动创建一个"test"的数据库,如果插入的集合不存在,也会自动创建。
在插入文档时,若没有指定"_id",MongoDB则会自动新增一个"_id"字段,其值是"ObjectId"类型,且在集合中是不能重复的,若指定"_id"字段,可以是字符串或数字类型。

2. save()
此方法为常用的插入方法之一,与insert()不同的是,使用insert()插入主键相同的文档时会报错,而使用save()插入主键相同的文档时会覆盖原文档。
(1)语法格式:

db.collection.save(
	<document>,
	{
		writeConncern:<document>
	}
)

(2)示例

db.Product.save(
  {
  	SysNo:2971,
  	ProductName:"DE-1300 Earbuds",
  	Weight:465,
  	Color:["Red","white"],
  	ProductMode:""
  }
)

3. insertOne()
同样是插入文档的方法,insertOne()只能插入一笔文档,如果用这个方法插入多笔文档,则MongoDB只会新增第一笔文档。
(1)语法格式

db.collection.insertOne(
	<document>,
	{
		writeConncern:<document>
	}
)

(2)示例

db.Product.insertOne(
  {
  	SysNo:2971,
  	ProductName:"DE-1300 Earbuds",
  	Weight:465,
  	Color:["Red","white"],
  	ProductMode:"Set"
  }
)

4.insertMany()
insertMany()可以插入多个文档,插入方法与insert()方法相同。
(1)语法格式

 db.collection.insertMany(
   [<document1>,[document2],...],
   {
      writeConcern: <document>,
      ordered:<boolean>
   }
)

(2)示例

db.Product.insertMany (
  [{
  	SysNo:2971,
  	ProductName:"DE-1300 Earbuds",
  	Weight:465,
  	Color:["Red","white"],
  	ProductMode:"Set"
  },
  {
  	SysNo:8622,
  	ProductName:"(Rose Gold) 16GB",
  	Weight:143,
  	Color:["Red","Blue"],
  	ProductMode:""
  }]
)
更新

在MongoDB中,常用的更新操作有update()和save(),除此之外,还有updateOne()、updateMany()和replaceOne()。
1. update()
在进行更新文档的操作时,可以通过特定条件来更新一个或多个文档。
(1)语法格式

db.collection.update(
	<query>,
	<update>,
	{
		upsert:<boolean>,
		multi:<boolean>,
		writeConcern:<document>,
		collation:<document>,
		arrayFilters:[<filterdocument 1>,...]
	}
)

(2)参数说明(前面有的不再赘述)

  • query:欲更新文档的条件。
  • update:更新文档的字段和值。
    — upsert:可选参数,默认为false。若设定为true,则表示在更新条件没有匹配时,会插入此文档。反之则不会。
    — multi:可选参数,默认为false。若设定为true,表示当更新条件匹配时,会更新全部匹配的文档,若为false,则只会更新匹配到的第1个文档。
  • collation:可选参数,用来指定更新的排序规则。
  • arrayFilters:MongoDB3.6版本才提供的可选参数,可以通过此参数进行条件筛选来更新数组中指定的元素。

(3)示例
将"Product"集合中"SysNo"为2971文档的"weight"的值改为1000

//需指定文档筛选条件,并且在"$set:{}"中设置要更新的文档内容
db.Product.update(
	{SysNo:2971},
	{$set:{Weight:1000}}
)

将名为"DE-1300 Earbuds"的产品颜色由"Red"改为"Orange",下面将介绍更新操作的arrayFilter用法。

db.Product.update(
	{ProductName:"DE-1300 Earbuds"},
	{$set:{"Color.$[i]":"Orange"}},
	{arrayFilters:[{i:{$eq:"Red"}}]}
)

在修改数组元素数据的语句中,“$ [i]“表示数组中元素的位置。如果使用”$[]”,则表示数组中所有元素,示例中的i为自定义变量,>用于arrayFilters参数对数组中的元素进行筛选。也可直接指定元素位置,"Color.1"指"Color"数组中第2个位置的元素。

2. save()
save()用来更新文档的话需注意一点的是必须加上"_id"字段,从而通过"_id"字段对原文档进行覆盖式更新。
(1)示例

db.Product.save(
  {
  	_id:ObjectId("62a71dce8a20f70af1cb09f2"),
  	SysNo:2971,
  	ProductName:"DE-1300 Earbuds",
  	Weight:1000,
  	Color:["Red","white"],
  	ProductMode:"Set"
  }
)

3. updateOne()
此方法智能更新一个文档。
(1)示例

db.Product.updateOne(
	{SysNo:2971},
	{$set:{Weight:1000}}
)

4. updateMany()
updateMany()方法可以同时更新多个文档,它与update()方法设定"multi"参数为true的用法一样。
(1)示例

db.Product.updateMany(
	{ProductMode:""},
	{$set:{ProductMode:"Set"}}
)

5. replaceOne()
replaceOne()方法与save()方法类似,都是使用覆盖的方式更新文档,不同的是,replaceOne()不需要指定"_id"字段,并且只更新匹配到的第一个数据。
(1)示例

db.Product.replaceOne(
	{ProductMode:""},
	{ProductMode:"Set"}
)
删除

MongoDB有3种常用的删除方法,分别为remove()、deleteOne()和deleteMany()。
1. remove()
remove()是最常用的删除文档方法,使用该方法可以删除指定条件的文档。
(1)语法格式:

db.collection.remove(
	<query>,
	{
		justOne:<boolean>,
		writeConcern:<document>,
		collation:<document>
	}
)

(2)参数说明(前面介绍过的参数不再赘述)

  • justOne:可选参数,默认为false,当设置为true时,则仅删除匹配到的第1个文档。为false时,则删除所有匹配的文档。

(3)示例

db.Product.remove(
	{ProductMode:""},
	{justOne:true}
)

如果删除语句为db.Product.remove({}),则删除全部的文档。

2. deleteOne()
deleteOne()方法只能删除第1个文档,此方法与remove()方法中设定"justOne"为true一样。
(1)示例

db.Product.removeOne(
	{_id:ObjectId("62a71dce8a20f70af1cb09f2")}
)

3. deleteMany()
使用deleteMany()可以一次删除多个文档。
(1)示例

db.Product.removeMany(
	{ProductMode:""}
)
查询

常用的基本查询有两种,分别为find()和findOne();
1. find()
(1)语法格式

db.collection.find(
	<query>,
	<projection>
)

(2)参数说明
projection参数可以指定查询结果中所需的字段。设置为1,表示显示此字段,设置为0,表示不显示此字段。

“_id"字段默认显示。投影时,”_id"为1的时候,其他字段必须是1;“_id"是0的时候,其他字段可以是0;如果没有”_id"字段约束,多个其他字段必须同为0或同为1。

(3)示例
查询"ProductMode"为空的文档,且只显示"SysNo"和"ProductMode"字段。

db.Product.find(
	{ProductMode:""},
	{_id:0,
	SysNo:1,
	ProductMode:1}
)

如果查询返回的条目数量较多,mongo shell则会自动实现分批显示。默认情况下每次只显示20条,可以输入"it"命令读取下一批。

如果你需要以易读的方式来读取数据,可以使用pretty()方法,语法格式如下:

db.collection.find().pretty()

2. findOne()
findOne()可以查询出符合条件的第一个文档,并且会以pretty()的方法呈现。
(1)示例

db.Product.findOne({ProductMode:""})

总结

以上就是今天要讲的内容,本文仅仅简单介绍了MongoDB以及它的简单使用,便于快速入门。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值