连接mongo数据库_MongoDB---基于分布式文件存储的数据库(四)(完)

f61347155a8a5ef8f44ff57893b8328b.png

MongoDB基础入门到高级进阶视频教程

【MongoDB】

十、集群

1. 复制集(Replication Set)

1.1 简介

MongoDB的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。建议提供仲裁节点,此节点不存储数据,作用是当主节点出现故障时,选举出某个备用节点成为主节点,保证MongoDB的正常服务。客户端只需要访问主节点或从节点,不需要访问仲裁节点。

MongoDB各个节点常见的搭配方式为:一主一从一仲裁、一主多从一仲裁、一主多从多仲裁。

主节点记录在其上的所有操作oplog(操作日志),从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

其结构如下:

fa9e35c3dea90c2e85bd1e3a9cef2835.png

1.2 搭建复制集

1)环境准备

搭建Replication Set可以使用多主机或单主机多端口的方式。本课程中使用单主机多端口方式搭建。

提供一个初始状态的MongoDB应用。

搭建Replication Set需要多个节点的环境尽可能保证一致,所以提供初始状态的MongoDB应用是最好的。

本环境中只安装一个MongoDB应用,通过多端口来多次启动MongoDB服务。

创建数据库目录:

  • mkdir -p data/db0 主节点
  • mkdir -p data/db1 从节点
  • mkdir -p data/db2 从节点
  • mkdir -p data/db3 仲裁节点

创建配置目录

mkdir etc

创建日志目录

mkdir log

创建进程文件目录

mkdir pids

2)配置文件

① Primary配置

vi etc/mongo0.conf

主节点配置文件如下:

  • dbpath=/opt/mongodb/data/db0 数据库目录
  • logpath=/opt/mongodb/log/mdb0.log 日志文件
  • pidfilepath=/opt/mongodb/pids/mdb0.pid 进程描述文件
  • bind_ip_all=true
  • directoryperdb=true 为数据库自动提供重定向
  • logappend=true 日志追加写入
  • replSet=rs0 复制集名称, 一个复制集中的多个节点命名一致。
  • port=37010 端口
  • oplogSize=10000 操作日志容量
  • fork=true 后台启动

② Secondary配置

vi etc/mongo1.conf

内容如下:

  • dbpath=/opt/mongodb/data/db1
  • logpath=/opt/mongodb/log/mdb1.log
  • pidfilepath=/opt/mongodb/pids/mdb1.pid
  • bind_ip_all=true
  • directoryperdb=true
  • logappend=true
  • replSet=rs0
  • port=37011
  • oplogSize=10000
  • fork=true

vi etc/mongo2.conf

内容如下:

  • dbpath=/opt/mongodb/data/db2
  • logpath=/opt/mongodb/log/mdb2.log
  • pidfilepath=/opt/mongodb/pids/mdb2.pid
  • bind_ip_all=true
  • directoryperdb=true
  • logappend=true
  • replSet=rs0
  • port=37012
  • oplogSize=10000
  • fork=true

③ Arbiter配置

vi etc/mongo3.conf

内容如下:

  • dbpath=/opt/mongodb/data/db3
  • logpath=/opt/mongodb/log/mdb3.log
  • pidfilepath=/opt/mongodb/pids/mdb3.pid
  • bind_ip_all=true
  • directoryperdb=true
  • logappend=true
  • replSet=rs0
  • port=37013
  • oplogSize=10000
  • fork=true

3)启动各节点

  • bin/mongod --config etc/mongo0.conf
  • bin/mongod --config etc/mongo1.conf
  • bin/mongod --config etc/mongo2.conf
  • bin/mongod --config etc/mongo3.conf

4)访问主节点

此节点作为主节点使用,连接方式为:

bin/mongo --port 端口 --host 地址

默认端口是27017,默认host是localhost

具体命令为: bin/mongo --port 37010 --host localhost

5)初始化复制集

使用命令初始化复制集:

rs.initiate({
    _id:"rs0",
    members:[
        {_id:0,host:"127.0.0.1:27101",priority:3},
        {_id:1,host:"127.0.0.1:27102",priority:2},
        {_id:2,host:"127.0.0.1:27103",priority:1},
        {_id:3,host:"127.0.0.1:27104",arbiterOnly:true}
     ]
});

初始化解释:

rs.initiate({  复制集初始化
     _id:"rs0",  复制集命名,与配置文件对应
    members:[   成员信息
         {_id:0,host:"127.0.0.1:37010",priority:3},  
_id:唯一标记,host:主机地址,priority:权重(复制集中工作的优先级,数字越大优先级越高) arbiterOnly:是否是仲裁节点
         {_id:1,host:"127.0.0.1:37011",priority:2},
         {_id:2,host:"127.0.0.1:37012",priority:1},
         {_id:3,host:"127.0.0.1:37013",arbiterOnly:true}
     ]
});

6)查看复制集状态

使用命令查看复制集状态:

rs.status();

7)查看当前连接节点是否是Primary节点

使用命令查看当前节点是否是主节点:

rs.isMaster();

8)测试主节点宕机情况

使用命令查看进程信息:

ps aux | grep mongod

将主节点对应的进程kill掉:

kill -9 主节点进程pid

访问复制集中原从节点:

bin/mongo --port 37011

查看当前节点是否是主节点:

rs.isMaster();

重新启动原主节点MongoDB

bin/mongod --config etc/mongo0.conf

连接新启动的节点

bin/mongo --port 37010

查看当前节点是否是主节点:

rs.isMaster();

1.3 总结

当主节点宕机时,仲裁节点会根据配置信息中的权重值优先选举权重高的节点作为主节点继续提供服务。当宕机的主节点恢复后,复制集会恢复原主节点状态,临时主节点重新成为从节点。

默认情况下直接连接从节点是无法查询数据的(db.集合名称.find()报错)。因为从节点是不可读的。如果需要在从节点上读取数据,则需要在从节点控制台输入命令rs.slaveOk([true|false])来设置。rs.slaveOk()或rs.slaveOk(true)代表可以在从节点上做读操作;rs.slaveOk(false)代表不可在从节点上做读操作。

slaveOk函数已经过时,现在推荐使用的是db.getMongo().setReadPref("nearest")来设置读操作逻辑。此函数在secondary节点中执行。参数可选值包括:primary(主节点读)、primaryPreferred(优先从主节点读)、secondary(从节点读)、secondaryPreferred(优先从从节点读)、nearest(在最近的节点读)。

2. 分片集群 shard cluster

2.1 什么是分片

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

分片结构如下:

73ac1a36260ecb1be19155f414930461.png

sharding方案将整个数据集拆分成多个更小的chunk,并分布在集群中多个mongod节点上,最终达到存储和负载能力扩容、压力分流的作用。在sharding架构中,每个负责存储一部分数据的mongod节点称为shard(分片),shard上分布的数据块称为chunk,collections可以根据“shard key”(称为分片键)将数据集拆分为多个chunks,并相对均衡的分布在多个shards上。

2.2 各术语解释

1) Shard

用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障

2) Config Server

mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

3) Routers

前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。

4) Shard Key

数据的分区根据“shard key”,对于每个需要sharding的collection,都需要指定“shard key”(分片键);分片键必须是索引字段或者为组合索引的左前缀;mongodb根据分片键将数据分成多个chunks,并将它们均匀分布在多个shards节点上。目前,mongodb支持两种分区算法:区间分区(Range)和哈希(Hash)分区。

5) Range分区

首先shard key必须是数字类型或字符串类型(字符串类型根据索引排序作为分裂依据),整个区间的上下边界分别为“正无穷大”、“负无穷大”,每个chunk覆盖一段子区间,即整体而言,任何shard key均会被某个特定的chunk所覆盖。区间均为左闭右开。每个区间均不会有重叠覆盖,且互相临近。当然chunk并不是预先创建的,而是随着chunk数据的增大而不断split。

6) Hash分区

计算shard key的hash值(64位数字),并以此作为Range来分区,基本方式同2.2.5;Hash值具有很强的散列能力,通常不同的shard key具有不同的hash值(冲突是有限的),这种分区方式可以将document更加随机的分散在不同的chunks上。

2.3 搭建分片集群

准备10个节点,1个路由routers;3个节点组成复制集作为配置服务器config server;3个节点组成复制集作为分片1,用于存储数据;3个节点组成复制集作为分片2,用于存储数据;分片1和分片2组成分片数据存储集群,和配置服务于路由组成完整的分配集群。

1)环境准备

分片0的3个节点的数据目录, RS复制集, 1主1备1仲裁

  • mkdir -p data/sh0/db0
  • mkdir -p data/sh0/db1
  • mkdir -p data/sh0/db2

分片1的3个节点的数据目录, RS复制集, 1主1备1仲裁

  • mkdir -p data/sh1/db0
  • mkdir -p data/sh1/db1
  • mkdir -p data/sh1/db2

配置服务器的3个节点的数据目录, RS复制集, 1主2备

  • mkdir -p data/cf/db0
  • mkdir -p data/cf/db1
  • mkdir -p data/cf/db2

路由节点,单节点

mkdir -p data/rt/db0

配置

mkdir etc

日志

mkdir log

进程描述文件

mkdir pids

2)搭建Shard

如Replication Set搭建过程,本案例中搭建2个Shard,每个Shard提供3个节点,1主1备1仲裁。

① 配置

sh0/db0配置 :

  • vi etc/sh0-db0.conf

内容: shardsvr=true 代表当前节点是一个shard节点。

  • dbpath=/opt/mongodb/data/sh0/db0
  • logpath=/opt/mongodb/log/sh0-db0.log
  • pidfilepath=/opt/mongodb/pids/sh0-db0.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh0
  • port=27010
  • oplogSize=10000
  • fork=true

sh0/db1配置 :

  • vi etc/sh0-db1.conf

内容:

  • dbpath=/opt/mongodb/data/sh0/db1
  • logpath=/opt/mongodb/log/sh0-db1.log
  • pidfilepath=/opt/mongodb/pids/sh0-db1.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh0
  • port=27011
  • oplogSize=10000
  • fork=true

sh0/db2配置 :

  • vi etc/sh0-db2.conf

内容:

  • dbpath=/opt/mongodb/data/sh0/db2
  • logpath=/opt/mongodb/log/sh0-db2.log
  • pidfilepath=/opt/mongodb/pids/sh0-db2.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh0
  • port=27012
  • oplogSize=10000
  • fork=true

sh1/db0配置 :

  • vi etc/sh1-db0.conf

内容:

  • dbpath=/opt/mongodb/data/sh1/db0
  • logpath=/opt/mongodb/log/sh1-db0.log
  • pidfilepath=/opt/mongodb/pids/sh1-db0.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh1
  • port=27020
  • oplogSize=10000
  • fork=true

sh1/db1配置 :

  • vi etc/sh1-db1.conf

内容:

  • dbpath=/opt/mongodb/data/sh1/db1
  • logpath=/opt/mongodb/log/sh1-db1.log
  • pidfilepath=/opt/mongodb/pids/sh1-db1.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh1
  • port=27021
  • oplogSize=10000
  • fork=true

sh1/db2配置 :

  • vi etc/sh1-db2.conf

内容:

  • dbpath=/opt/mongodb/data/sh1/db2
  • logpath=/opt/mongodb/log/sh1-db2.log
  • pidfilepath=/opt/mongodb/pids/sh1-db2.pid
  • bind_ip_all=true
  • shardsvr=true
  • logappend=true
  • replSet=sh1
  • port=27022
  • oplogSize=10000
  • fork=true

② 启动

  • bin/mongod --config etc/sh0-db0.conf
  • bin/mongod --config etc/sh0-db1.conf
  • bin/mongod --config etc/sh0-db2.conf
  • bin/mongod --config etc/sh1-db0.conf
  • bin/mongod --config etc/sh1-db1.conf
  • bin/mongod --config etc/sh1-db2.conf

③ 复制集设置

bin/mongo --port 27010

rs.initiate({
     _id:"sh0",
     members:[
         {_id:0,host:"127.0.0.1:27010",priority:2},
         {_id:1,host:"127.0.0.1:27011",priority:1},
         {_id:3,host:"127.0.0.1:27012",arbiterOnly:true}
     ]
});

bin/mongo --port 27020

rs.initiate({
     _id:"sh1",
     members:[
         {_id:0,host:"127.0.0.1:27020",priority:2},
         {_id:1,host:"127.0.0.1:27021",priority:1},
         {_id:3,host:"127.0.0.1:27022",arbiterOnly:true}
     ]
});

3) 搭建Config Server

同样搭建一个Replication Set作为配置服务器。config server的复制集中不允许有单仲裁节点。复制集初始化命令中,不允许设置arbiterOnly:true参数。1主2备

① 配置

vi etc/cf-db0.conf configsvr=true 代表当前节点是一个配置服务节点。

  • dbpath=/opt/mongodb/data/cf/db0
  • logpath=/opt/mongodb/log/cf-db0.log
  • pidfilepath=/opt/mongodb/pids/cf-db0.pid
  • bind_ip_all=true
  • logappend=true
  • replSet=cf
  • port=27030
  • oplogSize=10000
  • fork=true
  • configsvr=true

vi etc/cf-db1.conf

  • dbpath=/opt/mongodb/data/cf/db1
  • logpath=/opt/mongodb/log/cf-db1.log
  • pidfilepath=/opt/mongodb/pids/cf-db1.pid
  • bind_ip_all=true
  • logappend=true
  • replSet=cf
  • port=27031
  • oplogSize=10000
  • fork=true
  • configsvr=true

vi etc/cf-db2.conf

  • dbpath=/opt/mongodb/data/cf/db2
  • logpath=/opt/mongodb/log/cf-db2.log
  • pidfilepath=/opt/mongodb/pids/cf-db2.pid
  • bind_ip_all=true
  • logappend=true
  • replSet=cf
  • port=27032
  • oplogSize=10000
  • fork=true
  • configsvr=true

② 启动

  • bin/mongod --config etc/cf-db0.conf
  • bin/mongod --config etc/cf-db1.conf
  • bin/mongod --config etc/cf-db2.conf

③ 复制集设置

bin/mongo --port 27030

rs.initiate({
     _id:"cf",
     members:[
         {_id:0,host:"127.0.0.1:27030",priority:2},
         {_id:1,host:"127.0.0.1:27031",priority:1},
         {_id:3,host:"127.0.0.1:27032",priority:1}
     ]
});

4)搭建Router

① 配置

vi etc/rt-db0.conf

  • configdb=cf/127.0.0.1:27030,127.0.0.1:27031,127.0.0.1:27032
  • logpath=/opt/mongodb/log/rt-db0.log
  • pidfilepath=/opt/mongodb/pids/rt-db0.pid
  • port=27040
  • fork=true
  • bind_ip_all=true

② 启动

router启动的命令使用mongos。不再使用mongod命令。

bin/mongos --config etc/rt-db0.conf

分片集群搭建后,只是代表当前的集群可以实现分片,而不是集群中的每个集合默认分片。

③ 加入分片信息

连接Router节点

bin/mongo --port 27040

进入admin库

use admin

加入分片信息:

db.runCommand({'addShard':'sh0/127.0.0.1:27010,127.0.0.1:27011,127.0.0.1:27012'});

db.runCommand({'addShard':'sh1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022'});

④ 开启Shard

首先需要将Database开启sharding,否则数据仍然无法在集群中分布,即数据库、collection默认为non-sharding。对于non-sharding的database或者collection均会保存在primary shard上,直到开启sharding才会在集群中分布。

创建测试库

use test

开启Shard,开启分片命令必须在admin库下运行。

db.runCommand({ enablesharding: 'test'})

此后我们可以对collection开启sharding,在此之前需要先指定shard key和建立“shard key索引”,我们根据application对数据访问的模式,来设定shard key。

需要切换进入到对应的库中:

use test

db.users.ensureIndex({'alias':'hashed'});

设置集合为可分片集合的命令,必须在admin库中执行。

db.runCommand({ shardcollection: 'test.users', key: {'alias': 'hashed'}})

那么users集合将使用“alias”作为第一维shard key,采用hashed分区模式,将此chunk分裂成2个,我们可以通过sh.status()查看每个chunk的分裂区间。

十一、Spring Data Mongodb

使用Spring Data 框架都是按照面向对象思想操作用于的工具。

使用Spring Data Mongodb 也是使用面向对象的方式进行操作MongoDB,省略了使用Mongodb的Java客户端API把Document转换为实体类的过程

1. 创建项目

创建项目

2. 修改POM文件添加依赖

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

3. 修改配置文件

spring:
  data:
    mongodb:
      database: bjsxt
      host: 192.168.8.133
      username: root
      password: root
      port: 27017
      authentication-database: admin

2. MongoTemplate的使用

2.1 创建实体

@Document 参数表示操作的集合名称,如果没有@Document表示操作的集合名为实体类名首字母变小写(由大驼峰变成小驼峰)。
@Id 标识主键。当主键叫做_id或id时可以省略此属性
@Field 放在普通属性上,如果希望对属性改名或其他限制需要此注解。可以省略,表示实体类属性名为Mongodb集合中field名称
@Document("collection1")
public class People {
    @Id
    private String id;
    private String name;
    private int age;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "id='" + id + ''' +
                ", name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

2.2 添加文档

insert方法返回值是新增的Document对象,里面包含了新增后_id的值。

如果集合不存在会自动创建集合。通过Spring Data MongoDB还会给集合中多加一个_class的属性,存储新增时Document对应Java中类的全限定路径。这么做为了查询时能把Document转换为Java中类类型。

@Test
public void insert() {
    People people = new People();
    people.setAge(12);
    people.setName("测试名字");
    People people = mongoTemplate.insert(people);
}

2.3 修改文档

在Mongodb中无论是使用客户端API还是使用Spring Data,更新返回结果一定是受影响行数。如果更新后的结果和更新前的结果是相同,返回0。

如果使用对象方式进行修改(save方法)必须要保证对象中所有属性都是有值得,否则只能使用update方法

1)使用save修改

使用save时,如果主键值已经存在,则表示修改操作。

void contextLoads() {
    HousePojo hp = new HousePojo();
    hp.setId("5e478e0c41b522522ab11099");
    hp.setArea(129.0);
    hp.setHno("x003");
    hp.setTime(new Date());
    hp.setType("三室一厅");
    // 重点是返回的结果带有主键_id
    HousePojo hpResult = mongoTemplate.save(hp);
    System.out.println(hpResult);
}

2)使用特定运算符进行更新

底层使用mongodb更新运算符完成。

Update的set方法底层就是$set.可以通过set方法更新特定的属性值。

有两个更新方法:

  • updateFirst()只更新满足条件的第一个值
  • updateMulti() 更新所有满足条件的值

① updateFirst

使用Update设置修改结果时,注意update.set()函数第一个参数的类型。如果name是字符串取值张三要有双引号。如果set方法第一个参数是age,第二个参数要没有双引号。

// 设置查询体,查询条件具体内容
Criteria criteria = Criteria.where("name").is("张三");
// query设置查询条件
Query query = new Query(criteria);
// 设置修改哪些属性
Update update = new Update();
update.set("name","张三");
// People.class 告诉Spring Data MognoDB 上面的属性是哪个类。
// 类对应集合,就知道具体操作集合的哪个属性
UpdateResult result = mongoTemplate.updateFirst(query, update, People.class);
// 修改数量,如果修改前和修改后相同,返回0
System.out.println(result.getModifiedCount());
// 匹配数量。最多返回1,即使有多个张三返回也是1.
System.out.println(result.getMatchedCount());

② updateMulti

// 设置查询体,查询条件具体内容
Criteria criteria = Criteria.where("name").is("张三");
// query设置查询条件
Query query = new Query(criteria);
// 设置修改哪些属性
Update update = new Update();
update.set("age",18);
// People.class 告诉Spring Data MognoDB 上面的属性是哪个类。
// 类对应集合,就知道具体操作集合的哪个属性
UpdateResult result = mongoTemplate.updateMulti(query, update, People.class);
// 修改数量。返回所有匹配结果中真实被修改数量
System.out.println(result.getModifiedCount());
// 匹配数量
System.out.println(result.getMatchedCount());

2.4 删除

根据主键删除

使用remove(Object)实现根据主键进行删除。

只判断对象的主键,其他属性是否有值没有影响。但是主键必须不能是null的。

People peo = new People();
peo.setId("5e83fe26a7641113b6a4d71d");
peo.setName("随意");
DeleteResult result = mongoTemplate.remove(peo);
System.out.println(result.getDeletedCount());                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

2)根据条件进行删除

只要是Spring Data MongoDB中涉及到条件都提供了两种方式,一种根据POJO中属性名进行匹配,另一种是根据集合中属性名进行匹配。

① 修改POJO

此处特意把属性name配置@Field设置MongoDB集合中属性名称为username。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class People {
    // 主键可以叫做id也能映射上_id
    private String id;
    @Field("username")
    private String name;
    private Integer age;
    private String address;
}

② 通过实体类属性名设置条件

里面where方法参数name是People类的属性名。

remove方法第二个参数是类类型。

Query query = new Query(Criteria.where("name").is("张三"));
// 第二个参数告诉Spring Data Mongodb ,name属性对应的类类型。
DeleteResult result = mongoTemplate.remove(query, People.class);
System.out.println(result.getDeletedCount());

③ 通过集合属性名设置条件

其中where方法参数username是集合people的属性名

remove第二个参数是MongoDB中集合名称。

Query query = new Query(Criteria.where("username").is("张三"));
// 第二个参数告诉Spring Data Mongodb ,name属性对应的类类型。
DeleteResult result = mongoTemplate.remove(query,"people");
System.out.println(result.getDeletedCount());

2.5 查询文档

Criteria是标准查询的接口,可以引用静态的Criteria.where的把多个条件组合在一起,就可以轻松地将多个方法标准和查询连接起来,方便我们操作查询语句。

例如: 查询条件username="bjsxt"

mongoTemplate.find (new Query(Criteria.where("username").is("bjsxt")))

多个条件组合查询时:

例如:username="bjsxt" and userage="20"

mongoTemplate.find(new Query(Criteria.where("username").is("bjsxt").and("userage").is("20")))

例如:username="bjsxt" or userage="20"

mongoTemplate.findOne(new Query(new Criteria().orOperator(Criteria.where("username").is("bjsxt"),Criteria.where("userage").is("20"))));

1356d685b5f4c09531ace525d1734ceb.png

1) 查询全部文档

@Test
public void select() {
    List<People> list = mongoTemplate.findAll(People.class);
    System.out.println(list);
}

2)查询单个对象

如果查询结果是多个,返回其中第一个文档对象

@Test
void selectOne(){
    // 获取到结果中第一条数据
    // new Query() 表示没有条件
    People people = mongoTemplate.findOne(new Query(), People.class);
    System.out.println(people);
}

3)带有条件的查询多个

注意: 带有条件的查询多个时,使用find()方法

@Test
void find(){
    Query query = new Query(Criteria.where("age").gte(3));
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

4)根据主键进行查询

@Test
void findById(){
    People peo = mongoTemplate.findById("5e84317c2b937833016218bf", People.class);
    System.out.println(peo);
}

5)根据字段是否为空进行查询

@Test
void exists(){
    Query query = new Query(Criteria.where("age").exists(true));
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

6)根据大于并且小于查询

Criteria所有方法的返回值都是当前类对象,所以支持连缀写法。

@Test
void range(){
    Query query = new Query(Criteria.where("age").gte(1).lte(19));
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

7)根据正则查询(模糊查询)

@Test
void regex() {
    // java中正则不需要有//
    Query query = new Query(Criteria.where("name").regex("张"));
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

8)查询去重结果

findDistinct() 参数说明:

第一个参数: 查询条件query

第二个参数: 根据哪个属性去重。是POJO的属性名称。返回值为此属性去重后的集合。

第三个参数: 属性所在实体类。

第四个参数: 属性的类型,此类型作为结果中List集合的泛型。

@Test
void findDistinct(){
    List<String> list = mongoTemplate.findDistinct(new Query(), "name", People.class, String.class);
    System.out.println(list);
}

2.6 多条件查询

1)and

@Test
void and(){
    Criteria c = new Criteria();
    c.andOperator(Criteria.where("name").is("张三"),Criteria.where("age").is(18));
    Query query = new Query(c);
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

2)or

查询姓名为张三或者年龄是998岁的用户

@Test
void or(){
    Criteria c = new Criteria();
    c.orOperator(Criteria.where("name").is("张三"),Criteria.where("age").is(998));
    List<People> list = mongoTemplate.find(new Query(c), People.class);
    System.out.println(list);
}

3)混合应用

查询姓名为张三并且年龄为18岁或者姓名为李四年龄为20的用户

@Test
void orAnd(){

    Criteria and1 = new Criteria();
    and1.andOperator(Criteria.where("name").is("张三"),Criteria.where("age").is(18));
    Criteria and2 = new Criteria();
    and2.andOperator(Criteria.where("name").is("李四"),Criteria.where("age").is(20));

    Criteria c = new Criteria();
    c.orOperator(and1,and2);

    List<People> list = mongoTemplate.find(new Query(c), People.class);
    System.out.println(list);
}

2.7 结果排序

Sort只有私有构造,但是提供给了静态的by方法

Direction是Sort内部枚举。

age按照那个属性进行排序。属性一定是find方法第二个参数类中的属性。

@Test
void sort(){
    Query query = new Query(Criteria.where("age").gte(2));
    query.with(Sort.by(Sort.Direction.DESC,"age"));
    List<People> list = mongoTemplate.find(query, People.class);
    System.out.println(list);
}

2.8 分页查询

PageRequest是Pageable接口的实现类。里面有protected的构造方法和名称为of的静态方法。

PageRequest.of(page,size)

PageRequest.of(page,size,Sort) 先排序后分页

PageRequest.of(page,size,Direction,properties) 排序后分页

page表示第几页,0表示第一页

size表示一页显示几个

    @Test
    void page(){
        Query query = new Query();
//        query.with(PageRequest.of(0,2));
        query.with(PageRequest.of(0,2, Sort.Direction.DESC,"age"));
        List<People> list = mongoTemplate.find(query, People.class);
        System.out.println(list);
    }

2.9 聚合操作

1)查询文档总数

Aggregation.group(String ...)设置分组条件,如果没有分组,参数省略。

count() 取总条数

as() 给查询出来的总条数起别名

aggregate() 执行聚合命令,第二个参数Map表示返回结果放入到Map中。

result.getUniqueMappedResult() 获取到返回结果。

@Test
void aggregate(){
    TypedAggregation<People> aggregation  = TypedAggregation.newAggregation(People.class, Aggregation.group().count().as("count"));
    AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
    System.out.println(result.getUniqueMappedResult());
    System.out.println(result.getUniqueMappedResult().get("count"));
}

2)分组计算每组总数

此处要求group()参数必须是在People类中存在。

设置group参数,表示按照哪个属性进行分组。

getMappedResults() 当执行聚合函数返回结果为多行时使用此方法。

@Test
void aggregate(){
    TypedAggregation<People> aggregation  = TypedAggregation.newAggregation(People.class, Aggregation.group("name").count().as("count"));
    AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
    List<Map> list = result.getMappedResults();
    for(Map map : list){
        System.out.println(map.get("count")+"---"+map.get("_id"));
    }
}

3)带有查询条件的分组计算

Aggregation.match写在group前面表示先过滤条件在分组。写在后面表示先分组在过滤条件

@Test
void aggregate(){
    TypedAggregation<People> aggregation  = TypedAggregation.newAggregation(People.class,Aggregation.match(Criteria.where("name").is("张三")), Aggregation.group("name").count().as("count"));
    AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, Map.class);
    List<Map> list = result.getMappedResults();
    for(Map map : list){
        System.out.println(map.get("count")+"---"+map.get("_id"));
    }
}

需要更多Java学习资料的小伙伴可以私信我获取

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值