MongoDB介绍

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性 能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像 关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类 型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可 以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
说明:BSON是一种计算机数据交换格式,主要被用作MongoDB数据库中的数据存储和网络传输格式。 它是一种二进制表示形式,能用来表示简单数据结构、关联数组(MongoDB中称为“对象”或“文档”)以 及MongoDB中的各种数据类型。BSON之名缘于JSON,含义为Binary JSON(二进制JSON)。

特点

(1) 面向集合存储,易存储对象类型的数据

(2) 支持动态查询

(3) 支持完全索引,包含内部对象

(4) 支持复制和故障恢复

(5) 支持多种开发语言

(6) 使用高效的二进制数据存储,包括大型对象(如视频等)

适用场景

1)网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及 高度伸缩性。
2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓 存层可以避免下层的数据源过载。
3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对 MapReduce引擎的内置支持。

不适用的场景

1)要求高度事务性的系统。

2)传统的商业智能应用。

3)复杂的跨文档(表)级联查询。

相关概念

mongodb有哪些角色 mongodb类型_数据库

mongodb支持的数据类型

null

null用于表示空值或不存在的字段。

{"x" : null}

布尔类型

布尔型数据有true和false两个值。

{"x" : true}

数值类型

在Mongo shell中,默认使用64位浮点型数据。因此,会有以下两种数值形式:

{"x" : 2.32}//或{"x" : 2}

对于整数类型,可以使用NumberInt()(位有符号整型)或NumberLong()(8位有符号整型)方法进行转换。

{"x" : NumberInt(2)} 
{"x" : NumberLong(2)}

字符串

MongoDB中字符串类型使用UTF-8编码的字符表示。

{"x" : "123@qq.com"}

日期类型

MongoDB中日期使用时间戳表示,单位为毫秒,不存储时区

{"x" : new Date()}

创建日期对象时应该使用new Date(),而非构造函数Date()。将构造函数作为函数时返回的日期格式 是字符串,而非日期对象(与JavaScript工作机制有关)。

正则表达式

MongoDB中可使用与JavaScript相同的正则表达式进行查询筛选等

{"x" : /kaikeba/i}

数组

数据集可以用数组格式存储,与JavaSript中的数组表示相同

{"x" : ["kaikeba", "kaikeba.com"]}

内嵌文档

文档中可以嵌套一个子文档。在MongoDB文档总大小限制为16MB,建议使用子文档的形式组织数 据,子文档查询效率要高于多键查询

{"x" : {"kaikeba" : "kaikeba.com"}}

文档可以做为键的值,即:内嵌文档。MongoDB与关系型数据库相比,最大的优势就是内嵌文档。 与关系型数据库的扁平化数据结构相比,使用内嵌文档可以数据的组织方式更加自然

_id和ObjectId

MongoDB中每个文档都有一个"id"键,“id"可以是任何类型,不指”_id"时MongoDB会生成一个 ObjectId对象。。示例如下

{"_id" : ObjectId()}

ObjectId是一个12字节(24个十六进制数字)的存储空间,ObjectId的12字节数据组织方式如下

0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11     时间戳     |  机器码    |  PID  |  计数器

对于如下一个ObjectId,其各位字符含义为:

{"_id" : ObjectId("5444cce6aef53b0f343e2b9b")} 
/* 上面ObjectId各位字符含义如下 */ 
//5444cce6,第0〜3字节(第1〜8位)为时间戳 
//aef53b,第4〜6字节(第9〜14位)为机器码 
//0f34,第7〜8字节(第15〜18位)为进程ID 
//3e2b9b,第9〜11字节(第19〜24位)为自增计数器

代码

MongoDB的文档和代码中可以包括JavaScript代码

{"x" : function(){ /*这里是一段JavaScript代码*/}}

二进制数据

二进制数据是一个二进制字节的字作串,要保存非UTF-8字符到数据库中,只能使用十进制数据。

mongoDB常用指令

登录:

>mongo ip地址   //默认端口号27017
#注意:如果没有指定bind_ip,会导致mongodb默认绑定为127.0.0.1,导致外部无法访问 修改mongodb.conf文件:
bind_ip=0.0.0.0

退出:

>exit

查看数据库(数据库中至少有一条数据,此时的数据库才会显示出来)

>show dbs

切换数据库

>use 数据库名 
#这个指令也可以直接创建数据库,但只有添加数据后,show dbs才能看到该数据库

查看当前数据库,默认数据库:test

>db

查看所有的数据集

>show collections

删除当前数据库

>db.dropDatabase()

创建集合(相当于创建表)

>db.createCollection("user1")

删除集合

>db.collectionName.drop()

集合重命名

>db.oldCollectionName.renameCollection("newName")

新增数据

>db.collectionName.insert({"key":value,"key":value}) 或 >db.collectionName.save({"key":value,"key":value})

查询所有数据

>db.collectionName.find()

条件查询-find()以非结构化的方式展示文档

>db.collectionName.find({"age":26}) //查询等值关系 
>db.collectionName.find({age : {$gt : 100}})  // 大于100 
>db.collectionName.find({age : {$gte : 100}})  //大于等于100 
>db.collectionName.find({age : {$lt : 150}}) //小于150 
>db.collectionName.find({age : {$lte : 150}}) //小于等于150 
>db.collectionName.find({age : {$lt :200, $gt : 100}})  //大于100,小于200

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

>db.collectionName.find().pretty()

mongodb有哪些角色 mongodb类型_mongodb_02

and 关系
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件 语法:

>db.collectionName.find({key1:value1, key2:value2}).pretty()

or关系 MongoDB OR 条件语句使用了关键字 $or,语法格式如下:

>db.collectionName.find({$or: [ {key1: value1}, {key2:value2}]}).pretty()

mongodb有哪些角色 mongodb类型_mongodb_03

清空集合数据

>db.collectionName.remove({})
//条件删除:remove({key:value})
//删除满足条件的一条数据:remove({key:value},1)

查询一条数据

>db.collectionName.findOne();

查询指定列

> db.collectionName.find({},{name:1,age:1,sex_orientation:true})

查询指定字段的数据,并去重

> db.collectionName.distinct('sex')

对结果集排序

> db.collectionName.find().sort({salary:1})   //升序 > db.collectionName.find().sort({salary:-1}) //降序

mongodb有哪些角色 mongodb类型_数据_04

统计记录数

> db.collectionName.find().count()

查询限定条数

>db.collectionName.find().limit(number)

使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样 接受一个数字参数作为跳过的记录条数。

>db.collectionName.find().limit(NUMBER).skip(NUMBER)

更新数据

db.collectionName.update(<query>,<update>,{upsert: <boolean>, multi: <boolean>)

参数说明:
query: update的查询条件
update : update的对象和一些更新的操作符(如mongodb有哪些角色 mongodb类型_java_05inc…)等,也可以理解为sql update查询内set后面 的
upsert : 可选,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出 来多条记录全部更新。
示例:

> db.collectionName.update({name:'tom'},{$set:{age:23}},false,true)

Java调取mongoDB

添加mongodb-java-driver驱动包

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.11.0</version>
</dependency>

连接数据库并操作数据

首先,在mongodb.conf里增加bind_ip

mongodb有哪些角色 mongodb类型_数据_06

如果没有指定bind_ip,会导致mongodb默认绑定为127.0.0.1,导致外部无法访问

mongodb有哪些角色 mongodb类型_mongodb_07

public class Demo1 {
    public static void main(String[] args) {
        //建立mongodb的连接
        MongoClient mongoClient = new MongoClient("192.168.156.102", 27017);
        //得到数据源(库)
        MongoDatabase mydb1 = mongoClient.getDatabase("mydb1");
//        System.out.println(mydb1);
        //3、得到集合
//        mydb1.createCollection("user2");//创建新集合
        //得到现有集合
        MongoCollection<Document> users = mydb1.getCollection("users");
        //集合的CRUD
//        Document document = new Document("_id", 1101).append("name", "lisi").append("age", 30);
//        users.insertOne(document);
        System.out.println("成功");
        //        修改updateMany()多行  updateOne()单行
//        users.updateMany(Filters.eq("name","zhangsan"),new Document("$set",new Document("age",88)));
        //删除
        users.deleteOne(new Document("name","zhangsan"));
        //查询
        FindIterable<Document> documents = users.find();
        MongoCursor<Document> iterator = documents.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

增加执行成功后在mongodb客户端查看

mongodb有哪些角色 mongodb类型_mongodb_08

mongDB索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个 文件并选取那些符合查询条件的记录。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列 的值进行排序的一种结构。

创建索引的语法

>db.collection.createIndex(keys, options)

options取值的含义:

mongodb有哪些角色 mongodb类型_mongodb_09

mongodb有哪些角色 mongodb类型_数据_10

索引分类

(1) 默认索引 MongoDB有个默认的“id”的键,相当于“主键”的角色。集合创建后系统会自动创建一个索引在“id” 键上,它是默认索引,索引名叫“id”,是无法被删除的。我们可以通过以下方式查看:

>db.collectionName.getIndexes()

(2) 单列索引
在单个键上创建的索引就是单列索引,例如我们要在Users集合上给title键创建一个单列索引(1表示正序,-1逆序)

>db.collectionName.createIndex({"title":1})

(3) 组合索引

另外,我们还可以同时对多个键创建组合索引。如下代码创建了按照“UserId”正序,“UserName” 逆序的组合索引:

>db.collectionName.createIndex({"userid":1,"username":-1})

(4) 唯一索引

唯一索引限制了对当前键添加值时,不能添加重复的信息。值得注意的是,当文档不存在指定键 时,会被认为键值是“null”,所以“null”也会被认为是重复的,所以一般被作为唯一索引的键,最好都要 有键值对。

>db.collectionName.CreateIndex({"UserId":1}, { unique: true });

(5)TTL索引
TTL指生命周期的意思。即存储的document存储带有过期时间属性,超过生命周期自己主动删除。 像日志数据、系统自己主动产生的暂时数据、会话数据等均符合这一场景。 构建方式如:

>db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )

(6) 删除索引

新手常陷入的误区是,认为集合被删除,索引就不存在了。关系型数据库中,表被删除了,索引也 不会存在。在MongoDB中不存在删除集合的说法,就算集合数据清空,索引都是还在的,要移除索引 还需要手工删除。

>db.collectionName.dropIndexes()
#删除集合指定索引
>db.collectionName.dropIndex("索引名称")
#说明:drop()集合时,索引也会删除,remove()集合时,索引仍然存在

集群搭建

集群搭建方式之一就是mongoDB复制集,即一组mongod的进程。他们维护同一个数据集合。复制集 保证了数据的可靠性和高读取能力。

机制

一组复制集就是一组mongod实例管理同一个数据集,实例key在不同的机器上,实例包含主实例 (primary),接受所有的写操作,其他的属于副本实例(Secondary),从服务器保持与主服务器数据同步,类 似于redis中的主从复制。 每个复制集还有一个仲裁者(Arbiter),仲裁者的任务就是通过心跳机制来确认集群中集合的数量,并 在选举主服务器的过程中进行裁决。仲裁者并不存储数据,性质等价于redis中的哨兵机制

架构

在数据承载节点中,一个且只有一个成员被视为主节点,而其他节点则被视为辅助节点。节点接收所有 写入操作,一个副本集只能有一个主实例能够写入,主节点记录所有变更到它的记录

mongodb有哪些角色 mongodb类型_数据_11

辅助节点复制主节点的 oplog 并将操作应用于数据集

mongodb有哪些角色 mongodb类型_mongodb_12

也可以将一个额外的实例作为仲裁者添加到副本集。仲裁员不维护数据集,仲裁器的目的是通过响应其 他副本集成员的心跳和选择请求来维护副本集中的仲裁。因为它们不存储数据集,所以仲裁器是提供副 本集仲裁功能的一种好方法。
与具有数据集的完全功能副本集成员相比,仲裁器的资源成本更低,如果副本集的成员数为偶数,则添 加一个仲裁器以在初选中获得多数票。
当一个主服务器在超过配置的周期(默认为 10 秒)内未与该组的其他成员通信时,符合条件的辅助服 务器将要求选择将其自身指定为新的主服务器。集群试图完成新的初选并恢复正常操作。

mongodb有哪些角色 mongodb类型_mongodb_13

搭建步骤

(1)准备三台虚拟机服务器,并各自安装好mongoDB,保证三个服务器的防火墙都已关闭

192.168.132:27017

192.168.133:27017

192.168.134:27017

(2)修改mongodb.conf文件,添加replSet配置(三台都需要修改成同一个名称),然后启动服务器

#复制集名称 replSet=rep1

(3)初始化复制集 登录任意一台执行初始化操作

rs.initiate({_id:'rep1',members:[{_id:1,host:'192.168.197.132:27017'}, {_id:2,host:'192.168.197.133:27017'},{_id:3,host:'192.168.197.134:27017'}]})

(4)查看集群状态

rs.status()

(5)测试

#添加数据 db.users.insert({"name":"lisi","age":11}) #查询数据 db.users.find() 
#切换到从数据库查询数据 如果不允许查询,是因为默认情况下从数据库是不允许读写操作的,需要设置。 
>rs.slaveOK() 执行该命令后可以查询数据

(6)测试复制集主从节点故障转移功能

#关闭主数据库,注意从数据库的变化 
>db.shutdownServer()

(7) 主复制集添加仲裁者(arbiter)

现在我们的环境是一主两从,仲裁者对偶数集群有效。需要停止一个从机,在主服务器中运行下面命令

rs.remove(“ip:端口号”) //删除从节点

在一主一从关系中,任意节点宕机都无法选举出主节点,无法提供写操作,此时需要加入仲裁者节点即 可。

rs.addArb(“ip:端口号”)