Mongodb学习笔记

MongoDB,NoSql非关系型数据库,大数据基础课程,学习笔记

[TOC]

NoSQL简介

NoSQL(NoSQL = Not Only SQL ),意即”不仅仅是SQL”。
传统数据由关系数据库管理系统(RDBMS)来处理。

关系型数据库遵循ACID原则

  • A (Atomicity) 原子性

原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

  • C (Consistency) 一致性

一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

  • I (Isolation) 独立性

所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。

比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

  • D (Durability) 持久性

持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

分布式系统

分布式系统(distributed system)由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。
分布式系统是建立在网络之上的软件系统。

分布式计算的优点

  • 可靠性(容错)

分布式计算系统中的一个重要的优点是可靠性。一台服务器的系统崩溃并不影响到其余的服务器。

  • 可扩展性

在分布式计算系统可以根据需要增加更多的机器。

  • 资源共享

共享数据是必不可少的应用,如银行,预订系统。

  • 灵活性

由于该系统是非常灵活的,它很容易安装,实施和调试新的服务。

  • 更快的速度

分布式计算系统可以有多台计算机的计算能力,使得它比其他系统有更快的处理速度。

  • 开放系统

由于它是开放的系统,本地或者远程都可以访问到该服务。

  • 更高的性能

相较于集中式计算机网络集群可以提供更高的性能(及更好的性价比)。

分布式计算的缺点

  • 故障排除

故障排除和诊断问题。

  • 软件

更少的软件支持是分布式计算系统的主要缺点。

  • 网络

网络基础设施的问题,包括:传输问题,高负载,信息丢失等。

  • 安全性

开放系统的特性让分布式计算系统存在着数据的安全性和共享的风险等问题。

什么是NoSQL

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。

NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

RDBMS vs NoSQL

RDBMS

  • 高度组织化结构化数据
  • 结构化查询语言(SQL) (SQL)
  • 数据和关系都存储在单独的表中。
  • 数据操纵语言,数据定义语言
  • 严格的一致性
  • 基础事务

NoSQL

  • 代表着不仅仅是SQL
  • 没有声明性查询语言
  • 没有预定义的模式
  • 键 - 值对存储,列存储,文档存储,图形数据库
  • 最终一致性,而非ACID属性
  • 非结构化和不可预知的数据
  • CAP定理
  • 高性能,高可用性和可伸缩性

CAP定理

在计算机科学中, CAP定理(CAP theorem), 又被称作 布鲁尔定理(Brewer’s theorem), 它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
  • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)

根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA
    单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP
    满足一致性,分区容忍性的系统,通常性能不是特别高。
  • AP
    满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

NoSQL的优点/缺点

优点

  • 高可扩展性
  • 分布式计算
  • 低成本
  • 架构的灵活性,半结构化数据
  • 没有复杂的关系

缺点

  • 没有标准化
  • 有限的查询功能(到目前为止)
  • 最终一致是不直观的程序

流行的NoSql

SSDB

大数据前言

大数据概念

“大数据”(big data)是一个体量特别大,数据类别特别大的数据集。

大数据特点

  • 容量(Volume): 数据的大小决定所考虑的数据的价值和潜在的信息
  • 种类(Variety): 数据类型的多样性
  • 速度(Velocity):指获得数据的速度
  • 真实性(Veracity):数据的质量
  • 价值(Value):合理运用大数据,以低成本创造高价值

大数据应用场景

  • 医疗大数据 看病更高效
  • 零售大数据 最懂消费者
  • 电商大数据 精准营销法宝
  • 农牧大数据 量化生产
  • 交通大数据 畅通出行
  • 教育大数据 因材施教
  • 环保大数据 对抗PM2.5
  • 食品大数据 舌尖上的安全

集群(群集)Cluster

概念

多台计算机(服务器),一起对外提供服务

作用

  1. 更加可靠(Hight Avaliable 高可用)
  2. 解决单机硬件的物理上限
  3. 超级运算(超算)军工 科研

集群分类

主备集群(Master-Standby)

主从集群(Master-slave)

负载均衡集群

高性能计算集群

MongoDB

MongoDB的主页

MongoDB是一个高性能,开源,无模式的文档型NoSQL数据。

简介

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

主要功能特性

  1. 文件存储格式为BSON(一种JSON的扩展)
  2. 模式自由
  3. 支持动态查询
  4. 支持完全索引
  5. 支持复制和故障恢复
  6. 使用高效的二进制数据存储,包括大型对象(如视频等)
  7. 自动处理碎片,以支持云计算层次的扩展性
  8. 支持JAVA,RUBY,PYTHON,C++,PHP等多种语言
  9. 内部支持JavaScript

优势

  1. 查询速度快。
  2. 高并发。可以达到2万个并发
  3. 高容量。支持10TB以上的数据量

适用场景

  1. 网站数据
  2. 缓存
  3. 大尺寸、低价值的数据
  4. 高伸缩性的场景
  5. 用于对象及JSON数据的存储

使用限制

  1. 在32位系统上,不支持大于2.5G的数据
  2. 单个文件大小限制为16M
  3. 高度事务性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
  4. 传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。

MongoDB与关系型数据库对比

对比项 MongoDB MySQL、Oracle
数据库 数据库(dataBase) 数据库(dataBase、schema)
集合(collection) 二维表(table)
表中的一行数据 文档(document) 一条记录(record)
表字段 键(key) 列(column)
主外键 PK、FK
灵活度扩展性 极高

数据库

一个mongodb中可以建立多个数据库。

MongoDB的默认数据库为”db”,该数据库存储在data目录中。

MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串(””)。
  • 不得含有’ ‘(空格)、.、$、/、\和\0 (空字符)。
  • 应全部小写。
  • 最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

  • admin
    从权限的角度来看,这是root数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
  • local
    这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
  • config
    当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。

文档

文档是一组键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

RDBMS MongoDB
数据库 数据库
表格 集合
文档
字段
表联合 嵌入文档
主键 主键 (MongoDB 提供了 key 为 _id )
数据库服务和客户端
Mysqld/Oracle mongod
mysql/sqlplus mongo
  • 需要注意的是
  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
  • 文档键命名规范
  1. 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  2. .和$有特别的意义,只有在特定环境下才能使用。
  3. 以下划线_开头的键是保留的(不是严格要求的)。

集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

合法的集合名

  1. 集合名不能是空字符串""
  2. 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
  3. 集合名不能以”system.”开头,这是为系统集合保留的前缀。
  4. 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$

capped collections

Capped collections 就是固定大小的collection。

它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 “RRD” 概念类似。

Capped collections是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能 和标准的collection不同,你必须要显式的创建一个capped collection, 指定一个collection的大小,单位是字节。collection的数据存储空间值提前分配的。

要注意的是指定的存储大小包含了数据库的头信息。

  1. 在capped collection中,你能添加新的对象。
  2. 更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
  3. 不允许进行删除。使用rop()删除collection所有的行。
  4. 删除之后,你必须显式的重新创建这个collection。
  5. it机器中,capped collection最大存储为1e9( 1X109)个字节。

元数据

集合命名空间 描述
dbname.system.namespaces 列出所有名字空间。
dbname.system.indexes 列出所有索引。
dbname.system.profile 包含数据库概要(profile)信息。
dbname.system.users 列出所有可访问数据库的用户。
dbname.local.sources 包含复制对端(slave)的服务器信息和状态。

{ { system.indexes } }插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。

{ { system.users } }是可修改的。

{ { system.profile } }是可删除的。

MongoDB 数据类型

数据类型 描述
String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean 布尔值。用于存储布尔值(真/假)。
Double 双精度浮点值。用于存储浮点值。
Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array 用于将数组或列表或多个值存储为一个键。
Timestamp 时间戳。记录文档修改或添加的具体时间。
Object 用于内嵌文档。
Null 用于创建空值。
Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID 对象 ID。用于创建文档的 ID。
Binary Data 二进制数据。用于存储二进制数据。
Code 代码类型。用于在文档中存储 JavaScript 代码。
Regular expression 正则表达式类型。用于存储正则表达式。

ObjectId

ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:

  1. 前 4 个字节表示创建 unix时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
  2. 接下来的 3 个字节是机器标识码
  3. 紧接的两个字节由进程 id 组成 PID
  4. 最后三个字节是随机数

MongoDB 中存储的文档必须有一个_id键。这个键的值可以是任何类型的,默认是个 ObjectId 对象。

由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间

1
2
3
4
> var newObject = ObjectId()
> newObject.getTimestamp()

ISODate("2017-11-25T07:21:10Z")

ObjectId 转为字符串

1
2
3
> newObject.str

5a1919e63df83ce79df8b38f

字符串

BSON 字符串都是 UTF-8 编码。

时间戳

BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用,与普通的 日期 类型不相关。 时间戳值是一个 64 位的值。其中:

  • 前32位是一个 time_t 值(与Unix新纪元相差的秒数)
  • 后32位是在某秒中操作的一个递增的序数
    在单个 mongod 实例中,时间戳值通常是唯一的。

在复制集中, oplog 有一个 ts 字段。这个字段中的值使用BSON时间戳表示了操作时间。

BSON 时间戳类型主要用于 MongoDB 内部使用。在大多数情况下的应用开发中,你可以使用 BSON 日期类型。

日期

表示当前距离 Unix新纪元(1970年1月1日)的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。

MongoDB的安装

  1. 从官方获得MongoDB的压缩包
  2. 将其解压到 d:\,再重命名为mongo,路径为d:\mongo
  3. 创建MongoDB的数据文件夹

windows 下安装MongoDB

zip版,mis版本不再介绍

搭建文件目录路径如下

1
2
3
4
5
├─mongodb
│ └─bin
├─mongodbdata
├─mongodetc
└─mongodlog

mongodb 为主文件目录,其中 bin 为主要目录
mongodbdata 为数据库目录
mongodetc 为配置文件目录
mongodlog 为日志目录

  • 设置数据库位置
1
mongod.exe --dbpath G:\mongodb\mongodbdata
  • 设置目录文件

对应一个文件,而不是目录

1
mongod.exe --logpath g:\mongodb\mongodlog\mongodlog

另外可以书写配置文件编写bat批处理一键启动服务

  • 编写配置文件

mongod.cfg

1
2
3
4
5
systemLog:
destination: file
path: g:\mongodb\mongodlog\mongodlog
storage:
dbPath: g:\mongodb\mongodbdata
  • 以配置文件安装服务
1
mongod.exe --config "g:\mongodb\mongodetc\ongod.cfg" --install
  • 以配置文件启动服务
1
2
g:\mongodb\mongodb\bin\mongod.exe --config g:\mongodb\mongodetc\mongod.cfg

启动MongoDB服务端:

d:\mongo\bin\

1
mongod --dbpath=d:\db --logpath=c:\mongo\logs       \mongodb.log --port=27017

MongoDB命令参数说明

名称 说明
dbpath 数据文件存放路径,每个数据库会在其中创建一个子目录,用于防止同一个实例多次运行的mongod.lock 也保存在此目录中
logpath 日志文件
logappend 日志采用追加模式(默认是覆写模式)
bind_ip 对外服务的绑定ip,一般设置为空,及绑定在本机所有可用ip 上
port 对外服务端口。Web 管理端口在这个port 的基础上+1000
fork 以后台Daemon 形式运行服务
journal 开启日志功能,通过保存操作日志来降低单机故障的恢复时间
syncdelay 系统同步刷新磁盘的时间,单位为秒,默认是60 秒
directoryperdb 每个db 存放在单独的目录中,建议设置该参数
maxConns 最大连接数
repairpath 执行repair 时的临时目录。在如果没有开启journal,异常down 机后重启,必须执行repair操作

MongoDB - 连接

1
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
  • mongodb://
    这是固定的格式,必须要指定。
  • username:password@
    可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库
  • host1
    必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
  • portX
    可选的指定端口,如果不填,默认为27017
  • /database
    如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开 test 数据库。
  • ?options
    是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&;(分号)隔开
选项 描述
replicaSet=name 验证replica set的名称。 Impliesconnect=replicaSet.
slaveOk=true\ false 或 true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。false: 在 connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。
safe=true\ false 或 true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS).false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。
w=n 驱动添加 { w : n } 到getLastError命令. 应用于safe=true。
wtimeoutMS=ms 驱动添加 { wtimeout : ms } 到 getlasterror 命令. 应用于 safe=true.
fsync=true\ false 或 true: 驱动添加 { fsync : true } 到 getlasterror 命令.应用于 safe=true.false: 驱动不会添加到getLastError命令中。
journal=true\ false 或 如果设置为 true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true
connectTimeoutMS=ms 可以打开连接的时间。
socketTimeoutMS=ms 发送和接受sockets的时间。
  • 使用默认端口来连接 MongoDB 的服务
1
mongodb://localhost
  • 通过 shell 连接 MongoDB 服务
1
2
3
4
$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
...

MongoDB数据库基本命令:

  1. Help查看命令提示

db.help()

  1. 显示当前数据库的名字

db

  1. 切换/创建数据库

use 数据库名
当创建一个集合的时候会自动创建当前数据库

  1. 显示所有的数据库

show dbs

  1. 删除当前数据库

db.dropDatabase()

  1. 显示当前db状态

db.stats()

  1. 当前db版本

db.version()

  1. 查看当前db的链接机器地址

db.getMongo()

MongoDB操作集合(Collection)相关操作

  1. 创建集合

显示创建:

db.createCollection(“users”);

隐式创建(直接向集合插入数据):

db.users.insert({name:”suns”,age:10})

  1. 显示当前数据库中的所有集合

show collections
show tables

  1. 删除集合

db.users.drop()

MongoDB操作文档(Document)相关操作

  1. 创建文档

文档格式遵从json格式

db.users.insert({name:”suns”,age:10})
自动生成一个全球唯一的主键,文档主键_id:时间戳、机器、PID、计数器

  1. 删除文档

db.users.remove({})

db.users.remove({name:”suns”})

  1. 修改文档

db.users.update(query,update,upsert,multi)

query
修改的条件,若为{} 则全选

update
更新的命令

upsert
如果未发现符合要求的数据内容,是否进行插入操作,1或者true 进行插入,0或者false不进行插入

multi 是否进行多行更新,1或者true 进行多行更新,0或者false不进行多行更新

  1. 修改文档具体案例

db.users.update({name:”suns”},{$set:{password:”888”}},0, 1)

$set等同于sql语句中的set

$inc为对应key中的数据内容进行算数运算(增加)

db.users.update({},{$inc:{age:1},0,1})

MongoDB查询相关操作

基本查询操作

查询集合中所有内容:db.users.find();

查询集合中第一个内容:db.users.findOne();

条件查询

  • = 条件

- `!=` 条件 `$ne`

```db.users.find({name:{“$ne”:”suns”}})
  • > 条件 $gt

- `<` 条件 `$lt`

```db.users.find({age:{“$lt”:10}})
  • >= 条件 $gte

- `<=` 条件 `$lte`

```db.users.find({age:{“$lte”:10}})

逻辑运算

  • 与运算
1
db.users.find({name:”suns”,age:10})
  • 或运算

$or

1
db.users.find({$or:[{name:”suns1”},{age:32}]})   
  • 或非运算

$nor

1
db.users.find({$nor:[{name:”suns1”},{age:32}]})

集合运算

  • $in

类似于关系型数据库中的in操作

1
db.users.find({age:{$in:[23,24,25]}})
  • $all

主要用来查询数组中的包含关系,查询条件中只要有一个不包含就不返回

1
2
3
4
{"name":"suns1","post":[1,2,3]}
{"name":"suns1","post":[2,3,4]}
{"name":"suns1","post":[2,5,7]}
{"name":"suns1","post":[3,9,10]}
1
db.users.find({post:{$all:[2,3]}})

一行二行出现23

统计、排序、分页

  • 统计
1
2
3
db.users.count();//统计数据
db.users.find().count();
db.users.find({age:{$lt:5}}).count();//条件统计
  • 排序
1
2
db.users.find().sort({age:1}); //升序
db.users.find().sort({age:-1}); //降序
  • 分页
1
2
3
4
5
6
7
8
db.users.find().skip(2).limit(3); #从第三条开始,三个为一页
db.users.find().sort({age:-1}).skip(2).limit(3); #在上一个基础上以年龄为降序排列

#在上述基础进行统计
db.users.find().sort({age:-1}).skip(2).limit(3).count(0);
#忽略分页效果
db.users.find().sort({age:-1}).skip(2).limit(3).count(1);
#记录分页效果

特殊查询

  • 投影查询

排除某个列,类似于select 列名

1
db.users.find({},{_id:0})

$exists 判断一个key是否存在

1
db.users.find({name:{$exists:1}})

MongoDB的索引

概念

索引就是用来加速查询的。数据库索引与书籍的索引类似:有了索引就不需要翻遍整本书,数据库则可以直接在索引中查找,使得查找速度能提高几个数量级。在索引中找到条目以后,就可以直接跳转到目标文档的位置。

类似字典中拼音部首。

普通索引相关命令

  • 为某个键创建索引

默认为id创建索引

1
db.集合名称.ensureIndex({键值:1})
  • 查看关于索引的相关信息
1
db.集合名称.stats()
  • 查看查询使用索引的情况
1
db.集合名称.find({键值:value}).explain()
  • 删除索引
1
db.集合名称.ropIndex({键值:1})

删除集合,也会将集合中的索引全部删除

唯一索引相关命令

  • 创建唯一索引

保证每个键的唯一性


- 查看关于索引的相关信息

```db.集合名称.stats()
  • 查看查询使用索引的情况

- 删除索引

```db.集合名称.dropIndex({键值:1})

删除集合,也会将集合中的索引全部删除

MongoDB的复制

MongoDB的Master-Slave主从复制(已抛弃)

为什么需要复制

  1. 单节点故障(主备)
  2. 读写分离(主从)

MongoDB的复制架构

开发步骤

  1. 准备3个数据文件目录

mongodata1(主)mongodata2(从)mongodata3(从)

1
2
3
4
5
6
7
8
9
10
├─mongodb
│ └─bin
├─mongodbdata
│ ├─diagnostic.data
│ └─journal
├─mongodbdata1 #
├─mongodbdata2 #
├─mongodbdata3 #
├─mongodetc
└─mongodlog
1
2
3
4
5
mongod --dbpath="G:/mongodb/mongodbdata" --master --port 11111

mongod --dbpath="G:/mongodb/mongodbdata2" --slave --port 22222 --source 127.0.0.1:11111

mongod --dbpath="G:/mongodb/mongodbdata3" --slave –-port 33333 --source 127.0.0.1:11111

MongoDB的Replication Set副本集(已抛弃)

MongoDB主从复制的问题

主节点宕机,从节点不能对外提供服务,只能作为数据的备份

开发步骤

  1. 准备3个数据文件目录

mongodata1(主)mongodata2(从)mongodata3(从)

1
2
3
4
5
6
7
8
9
10
├─mongodb
│ └─bin
├─mongodbdata
│ ├─diagnostic.data
│ └─journal
├─mongodbdata1 #
├─mongodbdata2 #
├─mongodbdata3 #
├─mongodetc
└─mongodlog
1
2
3
mongod -port 11111 --dbpath="d:\mongodata1" --replSet baizhi
mongod -port 22222 --dbpath="d:\mongodata2" --replSet baizhi
mongod -port 33333 --dbpath="d:\mongodata3" --replSet baizhi

第一个服务器启动后作主节点执行下列代码

1
2
config_baizhi={"_id":"baizhi","members":[{_id:0,host:"localhost:11111"},{_id:1,host:"localhost:22222"}, {_id:2,host:"localhost:33333"}]};
rs.initiate(config_baizhi);

从节点需要执行 rs.slaveOK() 实现可读
查看节点状态 rs.status()

MongoDB的分片

为什么需要分片

一千万个文档中查找一条数据

将一千万个数据分成十个节点(服务器)每个100万条

  • 好处

提高查询效率,提高并发量

片键(分片的依据)

分片架构

先从ConfigDB读取片键后去查询

开发步骤

  • 准备三个数据库,configdb(配置库)、shard1(数据库1)、shard2(数据库2)
1
2
3
mongod --dbpath="d:/configdb" --port 11111
mongod --dbpath="d:/shard1" –port 22222
mongod --dbpath="d:/shard2" –port 33333
  • 启动mongos服务
1
mongos --port 44444 --configdb localhost:11111
  • 登录到mongos
1
mongo localhost:44444/admin
  • 指定存储数据的节点
1
db.runCommand({addshard:"localhost:22222",allowLocal:true})db.runCommand({addshard:"localhost:33333",allowLocal:true})
  • 指定分片的数据库
1
db.runCommand({"enablesharding":"baizhi"})
  • 指定分片的集合与片键
1
db.runCommand({"shardcollection":"baizhi.users","key":{"name":1}}) 
  • 数据插入测试

mongodb支持javascript语法

1
2
3
for (var i=0;i<100000;i++) {
db.users.insert({name:"hibiscidai"+i})
}

进入不同数据库节点进行统计数据查询,片键决定分区存储大小,根据实际需求。

MongoDB的JavaDriver

MongoDB数据结构在java中的映射存储

DBObject对象

1
2
3
4
5
6
7
{name:"suns",pwd:"123"}

Map.put("name","suns")

DBObject

BasicDBObject.put("name","suns")

BasicDBList对象(集合)

1
2
3
4
5
["suns","date1","date2"]

ArrayList

BasicDBlist.add("suns);

开发步骤

  • 导入jar包
  • 创建连接对象
1
MongoClient mongo = new MongoClient(ip,port);
  • 获取数据对象
1
DB db = mongo.getDB(“dbname”);
  • 获得Collection对象
1
DBCollection dbCollection = db.getCollection(“collectionName”);
  • 调用DBCollection对象的相关方法,完成CURD
1
2
3
4
5
dbCollection.insert()	→	db.users.insert()
dbCollection.find() → db.users.find()
dbCollection.findOne() → db.users.findOne()
dbCollection.update() → db.users.update()
dbCollection.remove() → db.users.remove()

Demo

插入一条文档(单条数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//db.users.insert({name:"suns",pwd:"123""});
@Test
public void testinsert1() {
MongoClient mongoClient = null;
try {
//连接到MOingoDB数据库
mongoClient = new MongoClient("127.0.0.1",27017);

//获取操作的目标数据库
DB db = mogoClient.getDB("hibiscidai");

//获取插入的集合目标
DBcollection collection = db.getCollection("users");

//准备数据
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("name","hibiscidai");
basicDBObject.put("age","20");

//执行操作
collection.insert(basicDBObject);
} catch (UnknownHostException e) {
e.printStackTrace();
} finally {
//关闭连接
mongoClient.close();
}
}

插入一条带集合的文档(带集合的单条数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//db.users.insert({name:"suna",post:"1,6,8,10"})
@Test
public void testinsert2() {
MongoClient mongoClient = null;

try {
//连接到MOingoDB数据库
mongoClient = new MongoClient("127.0.01",27017);

//获取操作的数据库
DB db = mogoClient.getDB("hibiscidai");

//获取插入的集合目标
DBcollection collection = db.getCollection("users");

//准备数据
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("name","suns")
BasicDBList basicDBList = new BasicDBList();
basicDBList.add(1);
basicDBList.add(6);
basicDBList.add(8);
basicDBList.add(10);
basicDBObject.put("post",basicDBList);

//执行操作
collection.insert(basicDBObject);
} catch (UnknownHostException e) {
e.printStackTrace();
} finally {
//关闭连接
mongoClient.close();
}
}

针对重复冗余操作代码进行封装工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MongoUtil {
// 一次连接设置
private static MongoClient mongonClient;

// 获取集合
public static DBCollection getCollection(String ip, Integer port, String dbName, String collectionName) {
// 连接数据库
DBCollection dBCollection = null;

try {
mongonClient = new MongoClient(ip, port.intValue());
// 获取数据库
DB getDb = mongonClient.getDB(dbName);
// 获取插入的目标集合
dBCollection = getDb.getCollection(collectionName);
} catch (UnknownHostException e) {
e.printStackTrace();
}

return dBCollection;
}

// 关闭连接
public static void closeConnection() {
mongonClient.close();
}
}

一次插入多个文档(多行数据插入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
public void testinsert3() {
MongoClient mongoClient = null;
try {
// 获取连接
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "hibiscidai", "users");

// 构建数据
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("name", "hibiscidai1");
DBObject basicDBObject1 = new BasicDBObject();
basicDBObject1.put("name", "hibiscidai2");
DBObject basicDBObject2 = new BasicDBObject();
basicDBObject2.put("name", "hibiscidai3");
// 创建list集合接收DBObject
List<DBObject> l = new ArrayList<DBObject>();
l.add(basicDBObject);
l.add(basicDBObject1);
l.add(basicDBObject2);

// 执行操作
collection.insert(l);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

有条件删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// db.users.remove({name:"zkf1"})
@Test
public void testdelete() {

try {
// 获取对应集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject对象
DBObject basicDBObject = new BasicDBObject();// {}
basicDBObject.put("name", "zkf1");
// 执行操作
collection.remove(basicDBObject);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

删除所有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// db.users.remove({})
@Test
public void testdelte2() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject对象
DBObject basicDBObject = new BasicDBObject();// {}
// 执行操作
collection.remove(basicDBObject);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// db.users.update({name:"zkf1"},{$set:{age:78}},0,1)
@Test
public void testupdate1() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("name", "zkf1");// {name:"zkf1"}
DBObject basicDBObject2 = new BasicDBObject();
basicDBObject2.put("age", 78);// {age:78}
DBObject basicDBObject3 = new BasicDBObject();
basicDBObject3.put("$set", basicDBObject2);// {$set:{age:78}}
// 执行操作
collection.update(basicDBObject, basicDBObject3, false, true);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

查询所有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// db.users.find();
@Test
public void testfind() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 执行命令
DBCursor dbCursor = collection.find();
// 每一个DBOBject对象对应一个文档
for (DBObject dbObject : dbCursor) {
System.out.println(dbObject);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

有条件的查询1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// db.users.find({name:"zkf3"})
@Test
public void testfind1() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject对象
BasicDBObject basicDBObject = new BasicDBObject();
basicDBObject.put("name", "zkf3");// {name:"zkf3"}
// 执行操作
DBCursor dbCursor = collection.find(basicDBObject);
for (DBObject dbObject : dbCursor) {
System.out.println(dbObject);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

有条件查询2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// db.users.find({age:{"$gte":38}})
@Test
public void testfind2() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("$gte", 38);// {"$gte":38}
DBObject basicDBObject2 = new BasicDBObject();
basicDBObject2.put("age", basicDBObject);// {age:{"$gte":38}}
// 执行操作
DBCursor dbCursor = collection.find(basicDBObject2);
for (DBObject dbObject : dbCursor) {
System.out.println(dbObject);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// db.users.find().skip(0).limit(3)
@Test
public void testfen() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 执行操作
DBCursor dbCursor = collection.find().skip(3).limit(3);
for (DBObject dbObject : dbCursor) {
System.out.println(dbObject);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// db.users.find().sort({age:-1})
@Test
public void testsort() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 创建BasicDBObject
DBObject basicDBObject = new BasicDBObject();
basicDBObject.put("age", 1);// {age:-1}
// 执行操作命令
DBCursor dbCursor = collection.find().sort(basicDBObject);
for (DBObject dbObject : dbCursor) {
System.out.println(dbObject);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}

统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// db.users.count()
@Test
public void testcount() {
try {
// 获取目标集合
DBCollection collection = MongoUtil.getCollection("127.0.0.1", 27017, "baizhi", "users");
// 执行操作命令
long l = collection.count();
System.out.println(l);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MongoUtil.closeConnection();
}
}
文章作者: HibisciDai
文章链接: http://hibiscidai.com/2018/04/21/2018-4-21-Mongodb学习笔记/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 HibisciDai
好用、实惠、稳定的梯子,点击这里