IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> mongodb的安装和使用 -> 正文阅读

[大数据]mongodb的安装和使用

作者:https://img-blog.csdnimg.cn/672ce16c61f94cb498ae6dd84ae01052.png

一、mongodb 介绍

  • mongodb是一个文档数据库(以json为数据模型),是一个介于关系型和非关系型数据库之间的产品,是非关系型数据库当中功能最丰富的。
  • 它支持的数据结构非常松散,数据格式是BSON(类似于json的二进制形式的存储格式),和json一样支持内嵌的文档对象和数组对象,因此可以存储比较复杂的数据类型
  • Mongodb最大的特点是支持的语言非常强大,基本支持所有的关系型数据库单表查询的大部分功能,而且支持数据建立索引。
  • 原则上oracle和mysql能做的事情,mongdb都能做(包括ACID事务)

1.1 结构

SQL概念Mongodb概念
数据库database数据库database
表table集合collection
行 row文档document
列 column字段 field
索引 index索引index
主键 primarykey_id 字段
视图 view视图 view
表连接 table joins聚合操作 $lookop

两者之间的结构:
在这里插入图片描述

1.2 MongoDB技术优势

  • mongodb基于灵活的json文档模型,适用于敏捷快速开发;
  • 与生俱来的高可用(备份,容灾)、高水平扩展能力(命令执行)方便能处理高并发和大数据量;
  • 可以把关系型数据库中多张表的数据放入在一个集合中,方便数据库的设计

1.3 MongoDB的应用场景

在这里插入图片描述
那如何选择是否使用MongoDB呢?
下面的只要满足一条就可以考虑使用了。
在这里插入图片描述

二、安装MongoDB

centos7 + MongoDB社区版本
下载位置:https://www.mongodb.com/try/download/community

自学的话,还是使用windows版本的,方便点!

2.1windows安装MongoDB

在这里插入图片描述
在这里插入图片描述
双击文件,下一步,点击complete
在这里插入图片描述

在这里插入图片描述

安装完成后查看系统服务是否注册和启动成功。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果按照上面流程所有步骤都成功了,说明mongodb已经启动成功了,那么这一步就非必须操作项,如果需要修改mongodb的IP端口、数据目录、日志目录等信息,可以继续往下看。

mongodb默认安装目录:C:\Program Files\MongoDB\Server\5.0\bin,可以从服务中查看到,配置文件为:mongod.cfg。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

至此,windows下安装启动mongodb就完成了!

2.2 Linux安装MongoDB

在这里插入图片描述

1.解压:tar -zxvf mongodb-linux-x86_64-rhel70-4.4.13.tgz

在这里插入图片描述

可以吧文件夹名字改成mongodb,简化名称

2.创建数据存储目录dbpath和日志存储目录logpath

# 创建数据存储目录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

注意:如果进入mongodb文件夹,那就不需要-p 来创建多级目录
在这里插入图片描述

在这里插入图片描述

此时可能报错:libcrypto.so.10: cannot open shared object file: No such file or directory
在这里插入图片描述

输入命令查看缺少什么数据源

# 路径是自己的mongodb安装路径
ldd /usr/local/mongodb/bin/mongod

在这里插入图片描述

此时可以手动安装这两个
yum install libcrypto.so.10
yum install libssl.so.10

但是此时报下面的错误:

CentOS Linux 8 - AppStream 错误:为仓库 ‘appstream‘ 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs

可以查看这一篇博客https://blog.csdn.net/wykqh/article/details/123004620

  1. 进入mongodb数据库
    bin/mogo

在这里插入图片描述

  1. 关闭mongodb
    方式一:
mongod --port=27017 --dbpath=/mongodb/data --shutdown

方式二:
进入mongo shell(sql命令栏)
先切库到admin,在关闭

use admin
db.shutdownServer()
exit

在这里插入图片描述

2.3 拓展

2.3.1 配置环境变量+配置文件 启动mongodb

1.添加环境变量
修改etc/profile,添加环境变量,方便执行mongodb命令

export MONGODB_HOME=/usr/local/mongodb
PATH=$PATH:$MONGODB_HOME/bin

export MONGODB_HOME 填写mongodb的安装路径

2.编辑/mongodb/conf/mongo.conf文件,内容如下(yaml格式):

vim /mongodb/conf/mongo.conf

i+复制下面的内容
esc ctrl+shift+; 输入wq 
保存退出

( /mongodb/conf/mongo.conf知道是mongodb的配置文件路径)
在这里插入图片描述
启动mongod

mongod -f /mongodb/conf/mongo.conf

2.3.2 关闭mongodb

按照上面的方法配置了配置文件的话,此时就可以用下面命令操作关闭( /mongodb/conf/mongo.conf知道是mongodb的配置文件路径)

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

在这里插入图片描述

三、Mongo shell使用

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

linux上面的连接数据库命令

mongo --port=27017

指定端口是27017,host连接的主机地址默认是127.0.0.1
在这里插入图片描述

windows上面打开shell界面

双击点mongo.exe
注意:mongo.exe 是用来启动MongoDB客户端。

在这里插入图片描述

在这里插入图片描述

常用命令:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、mongodb的安全认证

4.1 创建管理员账号

#设置管理员用户名密码需要 切换到admin库
use admin
#创建管理员
db.createUser({user:"root",pwd:"root",roles:["root"]})
#查看所有用户信息
show users
#删除用户
db.dropUser("root")

在这里插入图片描述

查看一下结果:

先启动mongodb
在这里插入图片描述
创建用户
在这里插入图片描述
可以看出来成功了,但是有一个问题,此时是可以直接输入mongo进去到shell页面的,如何解决了,那就是让mongodb按照权限认证的方式启动

4.2 权限认证方式启动mongodb

输入下面命令( /mongodb/conf/mongo.conf知道是mongodb的配置文件路径)

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

在这里插入图片描述
你在输入mongo会发现查看不到数据的!!

必须按照下面的方式登录

mongo -ufox -pfox --authenticationDatabase=admin

authenticationDatabase后面跟的是想要连接的数据库名
在这里插入图片描述

五、mongodb的文档操作

5.1 插入文档

3.2版本之后新增了db.collection.insertOne()和db.collection.insertMany()。

5.1.2 新增单个文档

  • insertOne:支持writeConcern(与事务有关)
db.collection.insertOne(
	<document>,
	{
		writeConcern: <docunment>
	}

)

writeConcern决定一个写操作落到多少个节点上才算成功,writeConcern的取值包括:
0:发起写操作,不关心是否成功
1:集群最大数据节点数,写操作需要被复制到指定节点数才算成功
majority:写操作需要被复制到大多数节点上才算成功

  • insert:若插入的数据主键已经存在,则会跑DuplicateKeyException异常,提示主键重复,不保存当前数据
  • save:如果_id主键存在则更新数据,如果不存在才插入数据(不建议使用了)
    在这里插入图片描述

5.1.3 批量(多个)新增文档

  • insertMany:向指定集合中插入多条文档数据
db.collection.insertMany(
	[ <document 1> , <document 2>, ... ],
	{
		writeConcern: <document>,
		ordered: <boolean>
	}
)

writeConcern:写入策略,默认为1,既既要求确认写操作; 0 是不要求;
ordered:指定是否按顺序写入,默认true,按顺序写入;

  • insert和save也可以实现批量插入

5.2 查询文档

find查询集合中的若干文档,语法格式如下:

db.collection.find(query, projection)
  • query:可选,使用查询操作符指定查询条件
  • projection: 可选,使用投影操作符指定返回的键。查询时返回文档中所有的键值,只需省略该参数即可(默认省略)。投影时,id为1的时候,其他字段必须是1;id是0的时候,其他字段可以是0;如果没有_id字段约束,多个其他字段必须同为0或同为1.

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

  1. findOne查询集合中的第一个文档
    语法格式如下:db.集合名.findOne(query, projection)

在这里插入图片描述
在这里插入图片描述

5.2.1 条件查询

  1. 指定条件查询
#查询带有nosql标签的book文档:
db.books.find({tag:"nosql"})
#按照id查询单个book文档:
db.books.find({_id:ObjectId("61caa09ee0782536660494d9")})
#查询分类为“travel”、收藏数超过60个的book文档:
db.books.find({type:"travel",favCount:{$gt:60}})
  1. 查询条件对照表
    |SQL |MQL |
    |–|--|
    |a=1 |{a: 1} |
    |a<>1 |{a: {KaTeX parse error: Expected 'EOF', got '}' at position 6: ne: 1}?} | |a>1 | {a…gt: 1}} |
    |a>=1 |{a: {KaTeX parse error: Expected 'EOF', got '}' at position 7: gte: 1}?} | |a<1 | {a…lt: 1}} |
    |a<=1 |{a: {$lte: 1}} |

  2. 查询逻辑对照表
    |SQL |MQL |
    |–|--|
    | a = 1 AND b = 1 | {a: 1, b: 1}或{KaTeX parse error: Expected 'EOF', got '}' at position 22: …{a: 1}, {b: 1}]}? | | a = 1 OR b…or: [{a: 1}, {b: 1}]} |
    | a IS NULL | {a: {KaTeX parse error: Expected 'EOF', got '}' at position 14: exists: false}?} | | a IN (1, …in: [1, 2, 3]}} |

  3. 查询逻辑运算符

  • $lt: 存在并小于
  • $lte: 存在并小于等于
  • $gt: 存在并大于
  • $gte: 存在并大于等于
  • $ne: 不存在或存在但不等于
  • $in: 存在并在指定数组中
  • $nin: 不存在或不在指定数组中
  • $or: 匹配两个或多个条件中的一个
  • $and: 匹配全部条件

5.2.2 排序&分页

  1. 指定排序
    在 MongoDB 中使用 sort() 方法对数据进行排序
#指定按收藏数(favCount)降序返回
db.books.find({type:"travel"}).sort({favCount:-1})
  1. 分页查询
    skip用于指定跳过记录数,limit则用于限定返回结果数量。可以在执行find命令的同时指定skip、limit
    参数,以此实现分页的功能。比如,假定每页大小为8条,查询第3页的book文档:
db.books.find().skip(8).limit(4)
  1. 正则表达式匹配查询
    MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。
//使用正则表达式查找type包含 so 字符串的book
db.books.find({type:{$regex:"so"}})
//或者
db.books.find({type:/so/})

5.3 更新文档

可以用update命令对指定的数据进行更新,命令的格式如下:

db.collection.update(query,update,options)

query:描述更新的查询条件;
update:描述更新的动作及新的内容;
options:描述更新的选项
- upsert: 可选,如果不存在update的记录,是否插入新的记录。默认false,不插入
- multi: 可选,是否按条件查询出的多条记录全部更新。 默认false,只更新找到的第一条记录
- writeConcern :可选,决定一个写操作落到多少个节点上才算成功。

更新操作符:

在这里插入图片描述

5.3.1 更新单个文档

某个book文档被收藏了,则需要将该文档的favCount字段自增

db.books.update({_id:ObjectId("61caa09ee0782536660494d9")},{$inc:{favCount:1}})

5.3.2 更新多个文档

默认情况下,update命令只在更新第一个文档之后返回,如果需要更新多个文档,则可以使用multi选
项。
将分类为“novel”的文档的增加发布时间(publishedDate)

db.books.update({type:"novel"},{$set:{publishedDate:new Date()}},{"multi":true})

multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件
查出来多条记录全部更新

update命令的选项配置较多,为了简化使用还可以使用一些快捷命令:
- updateOne:更新单个文档。
- updateMany:更新多个文档。
- replaceOne:替换单个文档。

5.3.3 使用upsert命令

upsert是一种特殊的更新,其表现为如果目标文档不存在,则执行插入命令。

db.books.update(
	{title:"my book"},
	{$set:{tags:["nosql","mongodb"],type:"none",author:"fox"}},
	{upsert:true}
)

nMatched、nModified都为0,表示没有文档被匹配及更新,nUpserted=1提示执行了upsert动作
在这里插入图片描述

5.3.4 实现replace语义

update命令中的更新描述(update)通常由操作符描述,如果更新描述中不包含任何操作符,那么
MongoDB会实现文档的replace语义

db.books.update(
	{title:"my book"},
	{justTitle:"my first book"}
)

5.3.5 findAndModify命令

findAndModify兼容了查询和修改指定文档的功能,findAndModify只能更新单个文档

//将某个book文档的收藏数(favCount)加1
db.books.findAndModify({
	query:{_id:ObjectId("61caa09ee0782536660494dd")},
	update:{$inc:{favCount:1}}
})

该操作会返回符合查询条件的文档数据,并完成对文档的修改。

在这里插入图片描述

默认情况下,findAndModify会返回修改前的“旧”数据。如果希望返回修改后的数据,则可以指定new选

db.books.findAndModify({
	query:{_id:ObjectId("61caa09ee0782536660494dd")},
	update:{$inc:{favCount:1}},
	new: true
})

与findAndModify语义相近的命令如下:
- findOneAndUpdate:更新单个文档并返回更新前(或更新后)的文档。
- findOneAndReplace:替换单个文档并返回替换前(或替换后)的文档。

5.4 删除文档

5.4.1 使用 remove 删除文档

  • remove 命令需要配合查询条件使用;
  • 匹配查询条件的文档会被删除;
  • 指定一个空文档条件会删除所有文档;
db.user.remove({age:28})// 删除age 等于28的记录
db.user.remove({age:{$lt:25}}) // 删除age 小于25的记录
db.user.remove( { } ) // 删除所有记录
db.user.remove() //报错

remove命令会删除匹配条件的全部文档,如果希望明确限定只删除一个文档,则需要指定justOne参
数,命令格式如下:

db.collection.remove(query,justOne)

例如:删除满足type:novel条件的首条记录

db.books.remove({type:"novel"},true)

5.4.2 使用 delete 删除文档

官方推荐使用 deleteOne() 和 deleteMany() 方法删除文档,语法格式如下:

db.books.deleteMany ({}) //删除集合下全部文档
db.books.deleteMany ({ type:"novel" }) //删除 type等于 novel 的全部文档
db.books.deleteOne ({ type:"novel" }) //删除 type等于novel 的一个文档

注意: remove、deleteMany等命令需要对查询范围内的文档逐个删除,如果希望删除整个集合,则使
用drop命令会更加高效

5.4.3 返回被删除文档

remove、deleteOne等命令在删除文档后只会返回确认性的信息,如果希望获得被删除的文档,则可以
使用findOneAndDelete命令

b.books.findOneAndDelete({type:"novel"})

除了在结果中返回删除文档,findOneAndDelete命令还允许定义“删除的顺序”,即按照指定顺序删除找
到的第一个文档

db.books.findOneAndDelete({type:"novel"},{sort:{favCount:1}})

remove、deleteOne等命令只能按默认顺序删除,利用这个特性,findOneAndDelete可以实现队列的
先进先出。

六、springboot整合MongoDB

第一步:引入依赖

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

第二步:配置yml

spring:
	data:
		mongodb:
			uri: mongodb://fox:fox@192.168.65.174:27017/test?authSource=admin
			#uri等同于下面的配置
			#database: test
			#host: 192.168.65.174
			#port: 27017
			#username: fox
			#password: fox
			#authentication-database: admin

连接配置参考文档:https://docs.mongodb.com/manual/reference/connection-string/

启动类启动,会发现

在这里插入图片描述

第三步:使用时注入mongoTemplate

@Autowired
MongoTemplate mongoTemplate;

第四步:操作

6.1 集合操作

@Autowired
MongoTemplate mongoTemplate;

@Test
public void testCollection(){
	boolean exists = mongoTemplate.collectionExists("emp");
	if (exists) {
		//删除集合
		mongoTemplate.dropCollection("emp");
	}
	//创建集合
	mongoTemplate.createCollection("emp");
}

6.2文档操作

相关注解

  • @Document
    修饰范围: 用在类上
    作用: 用来映射这个类的一个对象为mongo中一条文档数据。
    属性:( value 、collection )用来指定操作的集合名称

  • @Id
    修饰范围: 用在成员变量、方法上
    作用: 用来将成员变量的值映射为文档的_id的值

  • @Field
    修饰范围: 用在成员变量、方法上
    作用: 用来将成员变量及其值映射为文档中一个key:value对。
    属性:( name , value )用来指定在文档中 key的名称,默认为成员变量名

  • @Transient
    修饰范围:用在成员变量、方法上
    作用:用来指定此成员变量不参与文档的序列化

先创建一个实体类

@Document("emp") //对应emp集合中的一个文档
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
@Id //映射文档中的_id
private Integer id;
@Field("username")
private String name;
@Field
private int age;
@Field
private Double salary;
@Field
private Date birthday;
}

6.2.1 添加文档

insert方法返回值是新增的Document对象,里面包含了新增后id的值。如果集合不存在会自动创建集
合。通过Spring Data MongoDB还会给集合中多加一个class的属性,存储新增时Document对应Java中
类的全限定路径。这么做为了查询时能把Document转换为Java类型。

@Test
public void testInsert(){
	Employee employee = new Employee(1, "小明", 30,10000.00, new Date());
	//添加文档
	// sava: _id存在时更新数据
	//mongoTemplate.save(employee);
	// insert: _id存在抛出异常 支持批量操作
	mongoTemplate.insert(employee);
	List<Employee> list = Arrays.asList(
		new Employee(2, "张三", 21,5000.00, new Date()),
		new Employee(3, "李四", 26,8000.00, new Date()),
		new Employee(4, "王五",22, 8000.00, new Date()),
		new Employee(5, "张龙",28, 6000.00, new Date()),
		new Employee(6, "赵虎",24, 7000.00, new Date()),
		new Employee(7, "赵六",28, 12000.00, new Date()));
		//插入多条数据
		mongoTemplate.insert(list,Employee.class);
}

在这里插入图片描述

6.2.2 查询文档

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

@Test
public void testFind(){
	System.out.println("==========查询所有文档===========");
	//查询所有文档
	List<Employee> list = mongoTemplate.findAll(Employee.class);
	list.forEach(System.out::println);
	System.out.println("==========根据_id查询===========");
	//根据_id查询
	Employee e = mongoTemplate.findById(1, Employee.class);
	System.out.println(e);
	System.out.println("==========findOne返回第一个文档===========");
	//如果查询结果是多个,返回其中第一个文档对象
	Employee one = mongoTemplate.findOne(new Query(), Employee.class);
	System.out.println(one);
	System.out.println("==========条件查询===========");
	//new Query() 表示没有条件
	//查询薪资大于等于8000的员工
	//Query query = new Query(Criteria.where("salary").gte(8000));
	//查询薪资大于4000小于10000的员工
	//Query query = new Query(Criteria.where("salary").gt(4000).lt(10000));
	//正则查询(模糊查询) java中正则不需要有//
	//Query query = new Query(Criteria.where("name").regex("张"));
	//and or 多条件查询
	Criteria criteria = new Criteria();
	//and 查询年龄大于25&薪资大于8000的员工
	//criteria.andOperator(Criteria.where("age").gt(25),Criteria.where("salary").gt(8000));
	//or 查询姓名是张三或者薪资大于8000的员工
	criteria.orOperator(Criteria.where("name")
		.is("张三"),Criteria.where("salary").gt(5000));
	Query query = new Query(criteria);
	//sort排序
	//query.with(Sort.by(Sort.Order.desc("salary")));
	//skip limit 分页 skip用于指定跳过记录数,limit则用于限定返回结果数量。
	query.with(Sort.by(Sort.Order.desc("salary")))
		.skip(0) //指定跳过记录数
		.limit(4); //每页显示记录数
	//查询结果
	List<Employee> employees = mongoTemplate.find(
	query, Employee.class);
	employees.forEach(System.out::println);
}
@Test
public void testFindByJson() {
	//使用json字符串方式查询
	//等值查询
	//String json = "{name:'张三'}";
	//多条件查询
	String json = "{$or:[{age:{$gt:25}},{salary:{$gte:8000}}]}";
	Query query = new BasicQuery(json);
	//查询结果
	List<Employee> employees = mongoTemplate.find(
	query, Employee.class);
	employees.forEach(System.out::println);
}

6.2.3 更新文档

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

  • updateFirst() 只更新满足条件的第一条记录
  • updateMulti() 更新所有满足条件的记录
  • upsert() 没有符合条件的记录则插入数据(一定要设置id的值,要不然查询的时候会报错)
@Test
public void testUpdate(){
	//query设置查询条件
	Query query = new Query(Criteria.where("salary").gte(15000));
	System.out.println("==========更新前===========");
	List<Employee> employees = mongoTemplate.find(query, Employee.class);
	employees.forEach(System.out::println);
	Update update = new Update();
	//设置更新属性
	update.set("salary",13000);
	//updateFirst() 只更新满足条件的第一条记录
	//UpdateResult updateResult = mongoTemplate.updateFirst(query, update,Employee.class);
	//updateMulti() 更新所有满足条件的记录
	//UpdateResult updateResult = mongoTemplate.updateMulti(query, update,Employee.class);
	//upsert() 没有符合条件的记录则插入数据
	update.setOnInsert("id",11); //指定_id
	UpdateResult updateResult = mongoTemplate.upsert(query, update,Employee.class);
	//返回修改的记录数
	System.out.println(updateResult.getModifiedCount());
	System.out.println("==========更新后===========");
	employees = mongoTemplate.find(query, Employee.class);
	employees.forEach(System.out::println);
}


6.2.4 删除文档

@Test
public void testDelete(){
	//删除所有文档
	//mongoTemplate.remove(new Query(),Employee.class);
	//条件删除
	Query query = new Query(Criteria.where("salary").gte(10000));
	mongoTemplate.remove(query,Employee.class);
}


6.3 聚合操作

聚合操作处理数据记录并返回计算结果(诸如统计平均值,求和等)。聚合操作组值来自多个文档,可以对
分组数据执行各种操作以返回单个结果。聚合操作包含三类:单一作用聚合、聚合管道、MapReduce。

  • 单一作用聚合:提供了对常见聚合过程的简单访问,操作都从单个集合聚合文档。
  • 聚合管道是一个数据聚合的框架,模型基于数据处理流水线的概念。文档进入多级管道,将文档转
    换为聚合结果。
  • MapReduce操作具有两个阶段:处理每个文档并向每个输入文档发射一个或多个对象的map阶
    段,以及reduce组合map操作的输出阶段。

6.3.1 单一作用聚合

MongoDB提供 db.collection.estimatedDocumentCount(), db.collection.count(),
db.collection.distinct() 这类单一作用的聚合函数。 所有这些操作都聚合来自单个集合的文档。虽然这
些操作提供了对公共聚合过程的简单访问,但它们缺乏聚合管道和map-Reduce的灵活性和功能。

在这里插入图片描述

在这里插入图片描述

#检索books集合中所有文档的计数
db.books.estimatedDocumentCount()
#计算与查询匹配的所有文档
db.books.count({favCount:{$gt:50}})
#返回不同type的数组
db.books.distinct("type")
#返回收藏数大于90的文档不同type的数组
db.books.distinct("type",{favCount:{$gt:90}})

注意:在分片群集上,如果存在孤立文档或正在进行块迁移,则db.collection.count()没有查询谓词可能
导致计数不准确。要避免这些情况,请在分片群集上使用 db.collection.aggregate()方法。

6.3.2 聚合管道

6.3.2.1 什么是 MongoDB 聚合框架

MongoDB 聚合框架(Aggregation Framework)是一个计算框架,它可以:
- 作用在一个或几个集合上;
- 对集合中的数据进行的一系列运算;
- 将这些数据转化为期望的形式;
从效果而言,聚合框架相当于 SQL 查询中的GROUP BY、 LEFT OUTER JOIN 、 AS等。

6.3.2.2 管道(Pipeline)和阶段(Stage)

整个聚合运算过程称为管道(Pipeline),它是由多个阶段(Stage)组成的, 每个管道:
- 接受一系列文档(原始数据);
- 每个阶段对这些文档进行一系列运算;
- 结果文档输出给下一个阶段;
在这里插入图片描述
聚合管道操作语法

pipeline = [$stage1, $stage2, ...$stageN];
db.collection.aggregate(pipeline, {options})
  • pipelines 一组数据聚合阶段。除 o u t 、 out、 outMerge和$geonear阶段之外,每个阶段都可以在管道中
    出现多次。
  • options 可选,聚合操作的其他参数。包含:查询计划、是否使用临时文件、 游标、最大操作时
    间、读写策略、强制索引等等

在这里插入图片描述

6.3.2.3 常用的管道聚合阶段

聚合管道包含非常丰富的聚合阶段,下面是最常用的聚合阶段

阶段描述SQL等价运算符
$match筛选条件WHERE
$project投影AS
$lookup左外连接LEFT OUTER JOIN
$sort排序ORDER BY
$group分组GROUP BY
s k i p / skip/ skip/limit分页
$unwind展开数组
$graphLookup图搜索
f a c e t / facet/ facet/bucket分面搜索

文档:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

6.3.2.4 数据准备

准备数据集,执行脚本

var tags = ["nosql","mongodb","document","developer","popular"];
var types = ["technology","sociality","travel","novel","literature"];
var books=[];

for(var i=0;i<50;i++){
	var typeIdx = Math.floor(Math.random()*types.length);
	var tagIdx = Math.floor(Math.random()*tags.length);
	var tagIdx2 = Math.floor(Math.random()*tags.length);
	var favCount = Math.floor(Math.random()*100);
	var username = "xx00"+Math.floor(Math.random()*10);
	var age = 20 + Math.floor(Math.random()*15);
	var book = {
		title: "book-"+i,
		type: types[typeIdx],
		tag: [tags[tagIdx],tags[tagIdx2]],
		favCount: favCount,
		author: {name:username,age:age}
	};
	books.push(book)
}


db.books.insertMany(books);
  • $project
    投影操作, 将原始字段投影成指定名称, 如将集合中的 title 投影成 name
db.books.aggregate([{$project:{name:"$title"}}])

$project 可以灵活控制输出文档的格式,也可以剔除不需要的字段

db.books.aggregate([{$project:{name:"$title",_id:0,type:1,author:1}}])

从嵌套文档中排除字段

db.books.aggregate([
{$project:{name:"$title",_id:0,type:1,"author.name":1}}
])
或者
db.books.aggregate([
{$project:{name:"$title",_id:0,type:1,author:{name:1}}}
])
  • $match
    m a t c h 用 于 对 文 档 进 行 筛 选 , 之 后 可 以 在 得 到 的 文 档 子 集 上 做 聚 合 , match用于对文档进行筛选,之后可以在得到的文档子集上做聚合, matchmatch可以使用除了地理空间之
    外的所有常规查询操作符,在实际应用中尽可能将 m a t c h 放 在 管 道 的 前 面 位 置 。 这 样 有 两 个 好 处 : 一 是 可 以 快 速 将 不 需 要 的 文 档 过 滤 掉 , 以 减 少 管 道 的 工 作 量 ; 二 是 如 果 再 投 射 和 分 组 之 前 执 行 match放在管道的前面位置。这样有两个好处:一是 可以快速将不需要的文档过滤掉,以减少管道的工作量;二是如果再投射和分组之前执行 matchmatch,查询
    可以使用索引。
db.books.aggregate([{$match:{type:"technology"}}])

筛选管道操作和其他管道操作配合时候时,尽量放到开始阶段,这样可以减少后续管道操作符要操作的
文档数,提升效率

  • $count

计数并返回与查询匹配的结果数

db.books.aggregate([ {$match:{type:"technology"}}, {$count: "type_count"}
])

$match阶段筛选出type匹配technology的文档,并传到下一阶段;
$count阶段返回聚合管道中剩余文档的计数,并将该值分配给type_count

  • g r o u p 按 指 定 的 表 达 式 对 文 档 进 行 分 组 , 并 将 每 个 不 同 分 组 的 文 档 输 出 到 下 一 个 阶 段 。 输 出 文 档 包 含 一 个 i d 字 段 , 该 字 段 按 键 包 含 不 同 的 组 。 输 出 文 档 还 可 以 包 含 计 算 字 段 , 该 字 段 保 存 由 group 按指定的表达式对文档进行分组,并将每个不同分组的文档输出到下一个阶段。输出文档包含一个_id字 段,该字段按键包含不同的组。 输出文档还可以包含计算字段,该字段保存由 groupi?dgroup的_id字段分组的一些accumulator表达式的值。
    $group不会输出具体的文档而只是统计信息。
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ...
} }
  • id字段是必填的;但是,可以指定id值为null来为整个输入文档计算累计值。

  • 剩余的计算字段是可选的,并使用运算符进行计算。

  • _id和表达式可以接受任何有效的表达式。

  • accumulator操作符
    在这里插入图片描述
    g r o u p 阶 段 的 内 存 限 制 为 100 M 。 默 认 情 况 下 , 如 果 s t a g e 超 过 此 限 制 , group阶段的内存限制为100M。默认情况下,如果stage超过此限制, group100Mstagegroup将产生错误。但是,要
    允许处理大型数据集,请将allowDiskUse选项设置为true以启用$group操作以写入临时文件。

举例
  • book的数量,收藏总数和平均值
db.books.aggregate([
{$group:{_id:null,count:{$sum:1},pop:{$sum:"$favCount"},avg:
{$avg:"$favCount"}}}
]
  • 统计每个作者的book收藏总数
db.books.aggregate([
{$group:{_id:"$author.name",pop:{$sum:"$favCount"}}}
])
  • 统计每个作者的每本book的收藏数
db.books.aggregate([
{$group:{_id:{name:"$author.name",title:"$title"},pop:{$sum:"$favCount"}}}
])

  • 每个作者的book的type合集
db.books.aggregate([
{$group:{_id:"$author.name",types:{$addToSet:"$type"}}}
])

  • $unwind
    可以将数组拆分为单独的文档
    v3.2+支持如下语法:

{
$unwind:
{
#要指定字段路径,在字段名称前加上$符并用引号括起来。
path: <field path>,
#可选,一个新字段的名称用于存放元素的数组索引。该名称不能以$开头。
includeArrayIndex: <string>,
#可选,default :false,若为true,如果路径为空,缺少或为空数组,则$unwind输出文档
preserveNullAndEmptyArrays: <boolean>
} }

姓名为xx006的作者的book的tag数组拆分为多个文档

db.books.aggregate([
{$match:{"author.name":"xx006"}},
{$unwind:"$tag"}
])

每个作者的book的tag合集


db.books.aggregate([
{$unwind:"$tag"},
{$group:{_id:"$author.name",types:{$addToSet:"$tag"}}}
])

案例
示例数据

db.books.insert([
{
"title" : "book-51",
"type" : "technology",
"favCount" : 11,
"tag":[],
"author" : {
"name" : "fox",
"age" : 28
}
},{
"title" : "book-52",
"type" : "technology",
"favCount" : 15,
"author" : {
"name" : "fox",
"age" : 28
}
},{
"title" : "book-53",
"type" : "technology",
"tag" : [
"nosql",
"document"
],
"favCount" : 20,
"author" : {
"name" : "fox",
"age" : 28
}
}])


测试

# 使用includeArrayIndex选项来输出数组元素的数组索引
db.books.aggregate([
{$match:{"author.name":"fox"}},
{$unwind:{path:"$tag", includeArrayIndex: "arrayIndex"}}
])
# 使用preserveNullAndEmptyArrays选项在输出中包含缺少size字段,null或空数组的文档
db.books.aggregate([
{$match:{"author.name":"fox"}},
{$unwind:{path:"$tag", preserveNullAndEmptyArrays: true}}
])

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:37:48  更:2022-03-24 00:40:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:03:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码