【MongoDB入门】

2. MongoDB入门

在探花交友APP中,会涉及很多的数据保存,比如用户的动态,点赞信息,评论信息,位置信息等。这些数据有一下的特点:

  • 海量数据
  • 读多写少
  • 数据价值低
  • 地址位置相关数据
  • 更新十分频繁

针对上述特点,传统的MySQL数据库有些力不从心,因此,我们引入了MongoDB。

2.1 MongoDB简介

MongoDB:是一个高效的非关系型数据库(不支持表关系:只能操作单表)
在这里插入图片描述
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。

MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

2.1.1 MongoDB的存储模型

在这里插入图片描述
MongoDB采用的是内存和磁盘结合的存储方式,比较常用的数据都保存在内存中,如果内存中找不到数据,再去磁盘中查找,这样就加快了查询的速度。

为了保证数据的安全性,内存中的数据每一分钟都会同步到磁盘中。
此外,为了更加保护数据的安全性,MongoDB在新版本中引入了日志,日志在内存和硬盘中各一份,每10ms同步一次。这样即使断电的时候,内存中的数据没有保存到磁盘,也可以通过日志文件进行恢复,从而保证了数据的安全性。

但是即使这样,也不能MongoDB不能够保证数据100%不丢失。

在这里插入图片描述
此外,MongoDB支持数据分页技术,可以将保存的数据进行分页,从而可以非常方便的进行存储容量的扩充

2.1.2 MongoDB与其他数据库对比
  • 和Redis对比
    • Redis是纯内存数据库,存储容量有限
    • Redis支持的查询比较简单,而MongoDB支持结构化查询
  • 和MySQL对比
    • MongoDB不支持事务和联表查询
    • MongoDB支持动态字段,MySQL数据表一旦创建,很难修改字段
  • 查询效率
    • Redis > MongoDB > MySQL
2.1.3 MongoDB的应用
  • 游戏装备数据
    • 特征:修改频率很高
  • 物流行业数据
    • 特征:地理位置信息,海量数据
  • 直播打赏数据
    • 特征:数据量很大,修改频繁
  • 日志数据
    • 特征:数据量大,结构多变

2.2 MongoDB的数据和体系结构

下面是MongoDB和MySQL数据库概念上的对比
在这里插入图片描述
MongoDB中存储BSON数据,类似JSON
在这里插入图片描述
MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。

  1. MongoDB 的文档(document),相当于关系数据库中的一行记录。
  2. 多个文档组成一个集合(collection),相当于关系数据库的表。
  3. 多个集合(collection),逻辑上组织在一起,就是数据库(database)。
  4. 一个 MongoDB 实例支持多个数据库(database)。 文档(document)、集合(collection)、数据库(database)的层次结构如下图:

在这里插入图片描述
为了更好的理解,下面与SQL中的概念进行对比:

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument表中的一条数据
columnfield数据字段/域
indexindex索引
table joins表连接,MongoDB不支持
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

MongoDB中常用的数据结构如下:

MongoDB中常见的数据类型有:

  • 数据格式:BSON {aa:bb}
  • null:用于表示空值或者不存在的字段,{“x”:null}
  • 布尔型:布尔类型有两个值true和false,{“x”:true}
  • 数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用 NumberInt(4字节符号整数)或NumberLong(8字节符号整数), {“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
  • 字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}
  • 日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}
  • 正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相 同,{“x” : /[abc]/}
  • 数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}
  • 内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}
  • 对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }
  • 二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要 将非utf-字符保存到数据库中,二进制数据是唯一的方式。

2.3 MongDB的简单操作操作

2.3.1 新增数据

在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。

#插入数据
#语法:db.表名.insert(json字符串)
db.user.insert({id:1,name:'zhangsan'})  #插入数据
2.3.2 更新数据

update() 方法用于更新已存在的文档。语法格式如下:

db.collection.update(
   <query>,
   <update>,
   [
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   ]
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • update : update的对象和一些更新的操作符(如 , , ,inc.$set)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。
#更新数据
> db.user.update({id:1},{$set:{age:22}}) 

#注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})

#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据

#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})

#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)
2.3.3 删除数据

通过remove()方法进行删除数据,语法如下:

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

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
  • writeConcern :(可选)抛出异常的级别。

实例:

#删除数据
> db.user.remove({})

#插入4条测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})

> db.user.remove({age:22},true)

#删除所有数据
> db.user.remove({})
2.3.4 查询数据

MongoDB 查询数据的语法格式如下:

db.user.find([query],[fields])
  • query :可选,使用查询操作符指定查询条件
  • fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
    条件查询:
操作格式范例RDBMS中的类似语句
等于{<key>:<value>}db.col.find({"by":"Jack"}).pretty()where by = 'Jack'
小于{<key>:{$lt:<value>}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小于或等于{<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大于{<key>:{$gt:<value>}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大于或等于{<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等于{<key>:{$ne:<value>}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50

实例:

#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})

db.user.find()  #查询全部数据
db.user.find({},{id:1,username:1})  #只查询id与username字段
db.user.find().count()  #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2

#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1)  #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照id倒序排序,-1为倒序,1为正序

2.6、索引

索引能够极大提高查询的效率。类似于MySQL,MongoDB中叶提供了索引支持。在没有索引的时候,MongoDB需要便利整个集合,查询效率很低。
为MongoDB创建索引的命令如下,为age域设置一个递增的索引

#创建索引
#说明:1表示升序创建索引,-1表示降序创建索引。
> db.user.createIndex({'age':1})

3. MongoDB 集群

3.1 单机MongoDB存在的问题

单机MongoDB并不适用于企业场景,原因主要有以下两点:

  • 单点故障:MongoDB一旦发生宕机,则会导致应用的崩溃
  • 海量数据的存储问题:单机无法满足海量数据存储的需求。

为了解决上述的问题,便引入了MongoDB 集群。

3.2 MongoDB 集群的三种形式

  • 主从集群(Master-Slaver):是一种主从副本模式,现在已经弃用。
  • 副本集群(Replica Set):取代主从集群,可以解决单点故障的问题
  • 分片集群(Sharding):可以解决单点故障和海量数据存储的问题。

3.3 副本集群

副本集群有一下特点:

  • 一个集群中包含主节点和副本节点
  • 主节点只能有一个,可以完成数据的读写操作
  • 副本节点可以有多个,只能读取数据
  • 多个节点之间有心跳感应,并进行数据同步
  • 主节点宕机后,会自动从副本节点中选择一个成为主节点。

在这里插入图片描述
然而,尽管副本节点解决了单点故障的问题,但是并没有解决海量数据存储的问题。

3.4 分片集群

该模式适合存储海量数据,将数据分成不同的片,分别存储在不同的服务器上,从而实现容量的扩充。
在这里插入图片描述
分片集群包含三个重要的结构

  • 分片服务:用于保存数据片
  • 配置服务:当集群启动的时候,会读取分片的信息
  • 路由服务:根据客户端的请求,到配置服务中取选择合适的分片服务,然后将请求转发到对应的分片服务上。

此外,我们发现,一旦某一个分片服务宕机,那么数据就不完整了。因此在实际应用中,通常是结合分片集群和副本集群。对每一个分片服务设立副本集群,从而提高集群的健壮性。

MongoDB通过分片策略决定将数据保存到哪一个分片上。MongoDB有两种分片策略,根据集合字段来指定。

  • 范围指定:根据指定字段的数据按照范围进行划分,根据范围到不同的分片服务器读取数据
  • 数据哈希:根据指定字段进行哈希运算获取分片服务器

在这里插入图片描述

如上图所示,可以根据年龄进行分片。可以指定1-35岁的保存在分片1

在这里插入图片描述

也可以以id分片,利用哈希

4. Springboot整合MongoDB

Spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb-driver。在Springboot中使用MongoDB的步骤如下:

  • 导入依赖
  • 编写配置信息
  • 编写集合实体类
  • 注入MongoTemplate对象,完成CRUD操作

导入依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

编写application.yml

spring:
  data:
    mongodb:
      uri: mongodb://192.168.136.160:27017/test

编写集合对应的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(value="tb_person")
public class Person {
    @Id
    private ObjectId id;
    @Field("myname")
    private String name;
    private int age;
    private String address;
}
  • 只要是MongoDB的集合实体类,都需要添加@Document(value="XXX")注解,在MongoDB中,集合的名称就为XXX
  • 在实体类中,需要指定MongoDB的文档的ID,这个ID由MongoDB自动生成,不会重复。在ID字段上使用@Id指定。ID的类型应为ObjectId
  • 可以通过@Field("myname")来指定保存集合的域的名称,如果不指定,默认就以变量面作为域名

引入MongoTemplate

@Resource
private MongoTemplate mongoTemplate;

下面编写了一个测试类,来以Java代码的方式对MongoDB进行CRUD操作

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongoApplication.class)
public class MongoTest {

    @Resource
    private MongoTemplate mongoTemplate;

    @Test
    public void testInsert() {
        // 插入一条数据
        Person person = new Person();
        person.setAddress("上海");
        person.setAge(23);
        person.setName("Robert");
        this.mongoTemplate.save(person);
    }

    @Test
    public void testFindAll() {
        // 查询所有数据
        List<Person> all = this.mongoTemplate.findAll(Person.class);
        all.forEach(System.out::println);
    }

    @Test
    public void testFindByCondition() {
        // 根据条件查询
        Criteria criteria = Criteria.where("age")
                .is(23).and("myname").is("Robert");
        Query query = new Query(criteria);
        List<Person> people = this.mongoTemplate.find(query, Person.class);
        people.forEach(System.out::println);
    }

    @Test
    public void testFindPage() {
        int page = 2;
        int size = 5;
        // 条件分页
        Criteria criteria = Criteria.where("age").lt(55);
        Query query = new Query(criteria);
        query.skip((page - 1) * size).limit(size)
                .with(Sort.by(Sort.Order.desc("age")));
        List<Person> people = this.mongoTemplate.find(query, Person.class);
        people.forEach(System.out::println);
    }

    @Test
    public void testUpdate() {
        Query query = new Query(Criteria.where("id").is("63a431e998e6c17444113fc9"));
        // updateFirst是更新满足条件的第一个记录
        // 设置要更新的内容
        Update update = new Update();
        update.set("myname", "Jack");
        this.mongoTemplate.updateFirst(query, update, Person.class);
    }

    @Test
    public void testDelete() {
        // 根据条件删除
        Query query = new Query(Criteria.where("myname").is("Jack"));
        this.mongoTemplate.remove(query, Person.class);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于 MongoDB入门,你可以按照以下步骤进行学习: 1. 下载并安装 MongoDB:在 MongoDB 的官方网站上下载适合你操作系统的安装程序,并按照提示进行安装。 2. 启动 MongoDB 服务:安装完成后,启动 MongoDB 服务。在 Windows 上,你可以通过运行 `mongod` 命令启动服务。在 macOS 或 Linux 上,可以打开终端并运行 `mongod` 命令。默认情况下,MongoDB 会在本地的 27017 端口上启动。 3. 连接到 MongoDB:在另一个终端窗口或命令提示符中,使用 `mongo` 命令连接到 MongoDB。默认情况下,它会连接到本地的 MongoDB 服务器。 4. 创建数据库:在 `mongo` shell 中,可以使用 `use <database_name>` 命令创建一个新数据库,例如 `use mydb`。 5. 创建集合(表):集合类似于关系数据库中的表。你可以使用 `db.createCollection("<collection_name>")` 命令创建一个新集合,例如 `db.createCollection("mycollection")`。 6. 插入数据:使用 `db.<collection_name>.insertOne(<document>)` 命令将数据插入到集合中。例如,`db.mycollection.insertOne({ name: "John", age: 30 })`。 7. 查询数据:使用 `db.<collection_name>.find()` 命令查询集合中的所有数据。例如,`db.mycollection.find()`。 8. 更新数据:使用 `db.<collection_name>.updateOne(<filter>, <update>)` 命令更新集合中的数据。例如,`db.mycollection.updateOne({ name: "John" }, { $set: { age: 35 } })`。 9. 删除数据:使用 `db.<collection_name>.deleteOne(<filter>)` 命令删除集合中的数据。例如,`db.mycollection.deleteOne({ name: "John" })`。 这是一个 MongoDB 入门的基本流程。你可以根据需要进一步学习和探索 MongoDB 的更多功能和用法。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值