MongoDB学习记录

1、初识Mongo

概述:与关系型数据库不同,MongoDB 的数据以类似于 JSON 格式的二进制文档存储,通常称这种格式为Bson,Bson不仅支持JSON中已有的数据类型,还增加了一些额外的数据类型,例如日期和二进制数据,以提高存储效率和解析速度。。

文档型的数据存储方式的优势

  • 文档的数据类型可以对应到语言的数据类型,如数组类型(Array)和对象类型(Object)
  • 文档可以嵌套,有时关系型数据库涉及几个表的操作,在 MongoDB 中一次就能完成,可以减少昂贵的连接花销;
  • 文档不对数据结构加以限制,不同的数据结构可以存储在同一张表

使用场景

  • 网站数据

    Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性

  • 缓存

    由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载

  • 大尺寸、低价值的数据

    使用传统的关系型数据库存储一些大尺寸低价值数据时会比较浪费,在此之前,很多时候程序员往往会选择传统的文件进行存储

  • 高伸缩性的场景

    Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持以及集群高可用的解决方案

  • 用于对象及JSON 数据的存储

    Mongo 的BSON 数据格式非常适合文档化格式的存储及查询

MongoDB的应用

  • 游戏场景

    使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新

  • 物流场景

    使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。

  • 社交场景

    使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能

  • 物联网场景

    使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析

  • 直播

    使用 MongoDB 存储用户信息、礼物信息等

是否选用MongoDB:只要满足下表中的一个需求就可以使用:

应用特征Yes/No
应用不需要复杂事务及复杂join支持yes
新应用,需求会变,数据模型无法确定,想快速迭代开发
应用需要2000-3000以上的读写QPS(更高也可以)
应用需要TB甚至 PB 级别数据存储
应用发展迅速,需要能快速水平扩展
应用需要大量的地理位置查询、文本查询
应用需要99.999%高可用

MongoDB(MongoDB属于非关系型数据库)与关系型数据库的比较

Bson介绍:BSON是一种类似于JSON的二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类型。BSON有三个特点:轻量性、可遍历性、高效性。

数据类型说明document举例
String字符串{key:“cba”}
Integer整型数值{key:2}
Boolean布尔型{key:true}
Double双精度浮点数{key:0.23}
ObjectId对象id,用于创建文档的id{_id:new ObjectId()}
Array数组{arr:[“jack”,“tom”]}
Timestamp时间戳{ createTime: new Timestamp() }
object内嵌文档{student:{name:“zhangsan”,age:18}}
null空值{key:null}
Date或者ISODate日期时间{birthday:new Date()}
Code代码{setPersonInfo:function(){}}

2、Mongo的安装与启动

2.1、Mongo的安装

①、进入Mongo官网(Download MongoDB Community Server | MongoDB)

②、选择正确的版本下载(根据下图操作):

③、将下载的压缩包解压,再将解压后的目录重命名为一个简洁的名字后放入D盘根目录中(目录名不要带 . ):


2.2、Mongo的启动

2.2.1、启动方式一

启动命令

mongod.exe --dbpath=path --logpath=path
  • dbpath 指定数据存储位置
  • logpath 指定日志存储在哪个位置

注意:指定的路径一定要存在。

①、进入mongodb7_0_12目录(解压后重命名并放在D盘的目录),以cmd的方式打开:

点击路径位置输入cmd并回车:

此时就打开了cmd:

②、在mongodb7_0_12目录下新建两个目录,用于存放数据和日志:

由于日志是写入具体的文件,所以需要进入新建的log目录中新建一个文本文件用于保存日志:

③、在刚才打开的cmd命令行中启动mongo:

# 手动切换到bin目录
cd ./bin# 启动mongo并指定数据和日志的存放目录
mongod.exe --dbpath="D:\mongodb_5_0_28\data" --logpath="D:\mongodb_5_0_28\log\mylog.txt"

运行结果如下:

④、根据第一步的步骤再次打开一个cmd并输入如下命令以连接已启动的mongo数据库:

# 进入bin目录
cd ./bin# 启动mongo
mongo

运行结果如下:

⑤、通过如下命令查看所有的表:

show dbs;

运行结果如下:


2.2.2、启动方式二

①、完成启动方式一中的第②步,提前准备放数据和日志的目录以及存放日志的文件;

②、在mongodb_5_0_28目录下创建一个后缀为bat的文件,并写入如下内容后保存退出:

D:\mongodb_5_0_28\bin\mongod.exe --dbpath="D:\mongodb_5_0_28\data" --logpath="D:\mongodb_5_0_28\log\mylog.txt"

③、双击我们创建的start.bat文件,运行结果如下:

④、完成启动方式一中的第③步即可操作mongo了!


3、通过配置文件管理参数

问题

启动MongoDB时,编写参数太麻烦


解决方案

通过配置文件统一管理

①、首先在mongo的根目录下创建一个后缀名为conf的文件,创建完成后编辑该文件:

②、在文件中写入如下内容并保存退出(路径需要根据自己的实际情况改写):

# 数据库路径 
dbpath=D:\mongodb_5_0_28\data
# 日志输出文件路径
logpath=D:\mongodb_5_0_28\log\mylog.txt
# 错误日志采用追加模式 
logappend=true
# 启用日志文件,默认启用 
journal=true
# 这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false 
quiet=true
# 端口号 默认为27017 
bind_ip=0.0.0.0
# 启用权限验证,使用账号密码登录
# auth=true

③、修改mongo根目录下创建的start.bat文件:

D:\mongodb_5_0_28\bin\mongod -f D:\mongodb_5_0_28\mongo.conf

运行结果如下:

④、进入如下路径:D:\mongodb_5_0_28\bin,双击mongo.exe文件:

运行结果如下,说明我们的配置文件已经生效:


4、Linux安装Mongo

①、根据网络视频跟做完成一个Linux虚拟机的创建;

②、根据下图获取mongo的Linux版本地址(点击此处进入):

③、通过如下命令下载mongo:

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-5.0.28.tgz

如果报错说wget:未找到命令,先执行如下命令安装wget再执行上方的命令下载mongo:

yum install wget -y

运行结果如下:

④、解压下载的压缩文件并对解压后的文件重新命名:

tar -zxvf mongodb-linux-x86_64-rhel70-5.0.28.tgz 

运行结果如下:

对解压后的文件重命名:

mv mongodb-linux-x86_64-rhel70-5.0.28 mongodb5

运行结果如下:

⑤、将mongo的bin目录增加到环境变量中并生效配置文件:

# 进入mongo根目录下的bin目录
cd mongodb5/bin/# 获取bin目录的完整路径(将获取到的路径复制,后面要用)
pwd# 编辑配置文件
vi ~/.bash_profile# 进入文件后先按i切换到插入模式
i# 找到要修改的PATH属性进行修改(以下是我修改后的内容作为参考)
PATH=/home/muxi/mongodb5/bin:$PATH:$HOME/.local/bin:$HOME/bin# 修改完成后先按ESC键退出插入模式(ESC键在键盘左上角)
ESC# 输入:wq后回车即可保存并退出文件
:wq

修改后的文件内容如下:主要是将mongo目录下的bin目录添加到了PATH属性中,并用:将多个属性值进行分割:

通过如下命令生效配置文件:

. ~/.bash_profile

⑥、提前创建存放数据和日志的目录以及存放日志的文件:

# 由于要创建目录和文件,需要切换到管理员
sudo root# 创建多级目录
mkdir -p /var/mongo/data
mkdir -p /var/mongo/log# 创建存放日志的文件
touch /var/mongo/log/mylog.log

⑦、后台启动mongo:

# 后台运行mongo
mongod --dbpath /var/mongo/data/ --logpath /var/mongo/log/mylog.log -fork# 查看mongo进程验证是否启动成功
ps aux | grep mongod

运行结果如下:

⑧、连接mongo数据库:

mongo

运行结果如下:

此时,我们的mongo就完成了安装和启动,接下来可以考虑使用配置文件简化启动命令。

⑨、创建配置文件简化启动命令:

# 结束当前运行的mongo
Ctrl + C# 进入mongo的根目录
cd ..# 创建配置文件
touch mongo.cfg# 编辑配置文件
vim mongo.cfg

为文件添加的内容如下:

#数据库路径 
dbpath=/var/mongo/data
#日志输出文件路径
logpath=/var/mongo/log/mylog.log
#错误日志采用追加模式 
logappend=true
#启用日志文件,默认启用 
journal=true
#这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false 
quiet=true
#端口号 默认为27017 
bind_ip=0.0.0.0
port=27017

⑩、验证配置文件是否生效:

# 关闭以及启动的mongo进程
# 首先获取mongo的进程号
ps aux | grep mongodkill -9 mongod的进程号

运行结果如下:

并且输入mongo后也显示连接失败进一步说明我们已经成功关闭了mongo:

指定配置文件在后台运行:

mongod -f mongo.cfg --fork

运行结果如下:

连接数据库:

mongo

运行结果如下:


5、图形管理工具之Robo 3T

下载:https://download.studio3t.com/studio-3t/windows/2022.6.1/studio-3t-x64.zip

提示:安装时无脑下一步即可(可以调整软件的安装位置)。

实操:通过Robo 3T连接本地的mongo数据库(连接前一定要打开本地的mongo,可以直接打开前面创建的启动脚本D:\mongodb_5_0_28\start.bat)

测试结果如下

点击连接后,我们就可以通过Robo 3T对mongo数据库进行操作了!


6、MongoDB基础命令

①、查看数据库

概述:列出所有在物理上存在的数据库。

show dbs;

②、切换数据库/创建数据库

概述:如果数据库不存在,则指向数据库,但不会立即创建,直到插入数据或创建集合时数据库才被创建。

use 数据库名;

③、删除当前数据库

概述:删除当前指向的数据库,如果指向的数据库不存在,则什么也不做。

use 数据库名
db.dropDatabase()

④、创建集合

概述:创建一个集合。

注意:无需手动创建集合, 向不存在的集合中第一次添加数据时,集合会自动被创建出来。

db.createCollection("集合名")

⑤、查看集合

showtables;  // 只在老版本中支持
show collections;

⑥、删除集合

db.集合名.drop();

实操:通过图形管理工具Robo 3T实操基础命令(需要提前完成第5节的实操以连接本地的mongo数据库)。

提示:以下所有操作都在Robo 3T中的intelliShell中完成,下面是Robo 3T的使用说明:

1.查看所有的数据库:

show dbs;

运行结果如下:

2.切换数据库:

// 切换到存在的数据库local
use local;
//切换到不存在的数据库(即创建数据库)
use newdb

运行结果如下:

3.创建集合:

// 创建一个名为student的集合
db.createCollection("student")

运行结果如下:

由于我们是在新建的数据库中创建了集合,此时刷新数据库就能看到名为newdb的数据库了:

4.查看集合:

show collections;

运行结果如下:

5.删除集合:

db.student.drop();

运行结果如下:


7、文档的添加

概述:MongoDB中的数据以文档的形式存储,而MongoDB又将文档存储在集合中。集合类似于关系数据库中的表。如果集合不存在,MongoDB 会在首次存储该集合的数据时创建该集合。

语法

db.集合名.函数名()
函数名含义
save( )保存文档。文档不存在时,新创建一个文档; 文档存在,更新文档
insert( )插入文档,可以保存单文档,也可以是多文档
insertOne( )插入一个文档
insertMany( )插入多个文档

注意:插入文档时,如果不指定_id参数,MongoDB会为文档分配一个唯一的ObjectId。

实操:通过实操掌握如何为mongo添加文档。

// 创建并切换到一个新的数据库
use Tsinghua;// 为指定的集合添加文档
db.student.save({"name":"muxi","age":"24","score":"88"})

运行结果如下:

接下来查看文档内容:

student集合中的文档内容如下:

此时我们有一个新的需求,要求将name的值改为muxikeqi,根据上面表中提到的文档存在时,会更新文档,接下来执行如下程序来验证一下:

db.student.save({"name":"muxikeqi","age":"24","score":"88"})

运行后查看集合选项卡(查看时要按Ctrl+R进行刷新):

欸?怎么新增了一条数据,而不是修改原有数据?哦,原来mongo判断文档是否存在的依据是根据_id属性的值进行判断,因此要实现name属性值更改的需求时还要指定_id,完整代码如下:

// 这里的_id要根据自己操作时的_id属性的值进行修改
db.student.save({"_id" : ObjectId("66b40121db9f8c197f3ce023"),"name":"muxikeqi","age":"24","score":"88"})

运行结果如下:

运行后查看集合选项卡(查看时要按Ctrl+R进行刷新):

通过观察id和name属性的值,此时我们修改name属性值的需求已经正确实现了。

接下来尝试为已有集合student插入文档:

// insert()插入单条数据的格式与save()一样
db.student.insert({"name":"张三","age":"18","score":"90"})
// 插入多条数据时需要用[]将多组数据括起来
db.student.insert([{"name":"李四","age":"20","score":"92"},{"name":"王五","age":"23","score":"89"}])

运行后的集合选项卡(查看时要按Ctrl+R进行刷新):

最后实操一下inserOne()和insertMany(),其实它们的功能完全能通过insert()方法实现,这里主要是要了解:

db.student.insertOne({"name":"niko"})
db.student.insertMany([{"name":"donk","age":17},{"name":"magixx"}])

运行后的集合选项卡(查看时要按Ctrl+R进行刷新):


8、文档的修改

语法

db.集合名.函数名()
函数名含义
update( <query><update> ,{multi: <boolean>})参数query:查询条件,类似sql语句update中where部分
参数update:更新操作符,类似sql语句update中set部分
参数multi:可选,默认是false,表示只更新找到的第一条记录,值为true表示把满足条件的文档全部更新
updateOne( <query><update>)更新一条数据
updateMany( <query><update>)更新多条数据
replaceOne(<query><update>)只能更新整文档

提示:更新的字段若不存在,会生成一个相应字段。

实操:通过本实操掌握mongo如何修改文档。

首先尝试updata()方法的用法,将 集合下的 文档中 属性name的值为muxikeqi的值修改为muxi:

db.student.update({"name" : "muxikeqi"},{"name" : "muxi"})

修改后的集合选项卡(查看时要按Ctrl+R进行刷新):

通过观察上图不难得出结论:mongo中通过update()方法修改文档时,默认是更新整个文档,并且默认只会修改找到的第一个文档

下面先将第一条数据还原,方便后面的测试:

db.student.update({"name" : "muxi"},{"name" : "muxikeqi","age" : "24","score" : "88"})

接下来尝试只修改第一个name属性值为muxikeqi的age属性:

// 需要修改文档中单个属性值时可以通过$set属性实现
// 注意:即使指定的文档中没有age字段也会创建该字段并修改
db.student.update({"name" : "muxikeqi"},{$set:{"age" : 28}})

修改后的集合选项卡(查看时要按Ctrl+R进行刷新):

接下来尝试将所有name属性值为muxikeqi的age属性值修改为30:

// 同时修改多个文档时,需要添加{multi:true}
db.student.update({"name":"muxikeqi"} , {$set:{"age":30}} , {multi:true})

修改后的集合选项卡(查看时要按Ctrl+R进行刷新):

至此,我们已经了解了update()方法的默认机制,如何只修改文档中的单个属性,如何同时修改所有文档的操作方法。

下面了解一下updateOne()和updateMany()的用法,它们的功能都能通过update()方法实现:

db.student.updateOne({"name":"张三"},{$set:{"score":100}})
db.student.updateMany({"name":"muxikeqi"},{$set:{"score":99}})

修改前:

修改后:

最后了解一下replaceOne:

// 这里不用$set是因为会报错
db.student.replaceOne({"name":"李四"},{"age":25})

修改前:

修改后:


9、文档的删除

语法

db.集合名.函数名()
函数名含义
remove( <query>)参数query:匹配符合的删除条件数据
deleteOne( <query>)更新一条数据
deleteMany( <query>)更新多条数据

实操:通过本实操掌握mongo中删除文档的方法(需要提前拷贝多份,方便后期的学习):

// remove()默认删除多个文档
db.student.remove({"name":"muxikeqi"})
// deleteOne()默认删除一个文档
db.student.deleteOne({"score":100})
// deleteMany()默认删除多个文档
db.student1.deleteMany({"name":"muxikeqi"})

student集合运行后的结果为:

student1运行后的结果:

接下来尝试删除集合中的所有文档:

// 两种方法的{}都不能省略,否则会报错
db.student.remove({})
db.student1.deleteMany({})

运行后两个集合都没有任何文档:


10、文档的查询

概述:若要从集合中选择文档,可以使用 find() 或者 findOne() 方法。若要选择集合中的所有文档,请将空文档作为查询筛选器文档传递给该方法。

语法

db.集合名.函数名()
函数名含义
find( <{条件文档}>)查找到所有匹配数据
findOne( <{条件文档}>)只返回匹配的第一个数据

运算符

语法操作格式
$eq等于{:}
$lt小于{:{$lt:}}
$lte小于或等于{:{$lte:}}
$gt大于{:{$gt:}}
$gte大于或等于{:{$gte:}}
$ne不等于{:{$ne:}}
$or{$or:[{},{}]}
$in在范围内{age:{$in:[val1,val2]}}
$nin不在范围内{age:{$nin:[val1,val2]}}

模糊匹配

概述:使用//或$regex编写正则表达式。

示例

db.person.find({name:/^zs/})
db.person.find({name:{$regex:'^zs'}}})

自定义查询

概述:使用$where后面写一个函数,返回满足条件的数据

示例

db.person.find({$where:function(){return this. Age>20}}) # 高版本已经不支持了
db.person.find({$where:"this.age==23"});
db.person.find("this.age >23");
db.person.find('this.country=="吴国" || this. Age==23');

limit

概述:用于读取指定数量的文档。

语法

db.集合名称.find().limit(NUMBER)

skip

概述:用于跳过指定数量的文档。

语法

db.集合名称.find().skip(2)

sort

概述:用于对结果集进行排序。

语法

db.集合名称.find().sort({字段:1,...})
  • 参数为1时表示升序排列
  • 参数为-1时表示降序排列

count

概述:用于统计结果集中文档条数。

语法及演示

db.集合名称.find({条件}).count()
db.集合名称.count({条件})db.stu.find({gender: true}).count()
db.stu.count({age:{$gt:20},gender: true})

$exists

概述:判断是否有某个字段。

语法

db.集合名称.find({'field':{$exists: true}})

dictinct

概述:用于去重。

语法

db.集合名称.distinct(field)
db.集合名称.distinct(field,{过滤条件  })

实操前准备:准备用于查询的集合,并为集合添加文档:

// 为集合添加数据用于后期查询
db.person.insert([{"name":"司马懿","country":"魏国","age":35},
{"name":"张辽","country":"魏国","age":34},
{"name":"徐晃","country":"魏国","age":24},
{"name":"夏侯惇","country":"魏国","age":23},
{"name":"夏侯渊","country":"魏国","age":23},
{"name":"庞德","country":"魏国","age":23},
{"name":"张郃","country":"魏国","age":34},
{"name":"李典","country":"魏国","age":41},
{"name":"乐进","country":"魏国","age":34},
{"name":"典韦","country":"魏国","age":12},
{"name":"曹洪","country":"魏国","age":21},
{"name":"曹仁","country":"魏国","age":11},
{"name":"诸葛亮","country":"蜀国","age":20},
{"name":"关羽","country":"蜀国","age":32},
{"name":"张飞","country":"蜀国","age":23},
{"name":"马超","country":"蜀国","age":53},
{"name":"黄忠","country":"蜀国","age":23},
{"name":"赵云","country":"蜀国","age":32},
{"name":"魏延","country":"蜀国","age":42},
{"name":"关平","country":"蜀国","age":12},
{"name":"周仓","country":"蜀国","age":42},
{"name":"关兴","country":"蜀国","age":23},
{"name":"张苞","country":"蜀国","age":12},
{"name":"周瑜","country":"吴国","age":32},
{"name":"吕蒙","country":"吴国","age":11},
{"name":"甘宁","country":"吴国","age":23},
{"name":"太史慈","country":"吴国","age":23},
{"name":"程普","country":"吴国","age":24},
{"name":"黄盖","country":"吴国","age":28},
{"name":"韩当","country":"吴国","age":23},
{"name":"周泰","country":"吴国","age":29},
{"name":"蒋钦","country":"吴国","age":19},
{"name":"丁奉","country":"吴国","age":17},
{"name":"徐盛","country":"吴国","age":27}
])

实操:通过本实操掌握mongo查询数据的方法。

首先尝试用find()获取全部的文档:

db.person.find()

运行结果如下:

接下来用findOne()获取所有的文档:

db.person.findOne()

运行结果如下:

总结:在查询所有文档时,用find()查询时能获取集合中所有的文档,而用findOne()查询时只能获取到第一个文档。

下面尝试获取指定条件的文档:

// 获取集合中age属性小于12的所有文档
db.person.find({"age":{$lt:12}})

运行结果如下:

下面尝试有多个判断条件时有一个满足条件即可的情况(下面演示age属性的值小于12或大于50的情况):

db.person.find({$or:[{"age":{$lt:12}},{"age":{$gt:50}}]})

运行结果如下:

下面尝试判断条件的同一属性满足多个特定值即可的情况:

db.person.find({"age":{$in:[34,35,36]}})

运行结果如下:

下面尝试利用模糊匹配查询所有name值第一个字是 '张' 的文档:

db.person.find({"name":/^张/})

运行结果如下:

下面展示模糊匹配的另一种写法:

db.person.find({"name":{$regex:"^周"}})

运行结果如下:

下面演示limit()方法获取指定条数的数据:

// 获取匹配到的前三条数据(前三个文档)
db.person.find().limit(3)

运行结果如下:

下面演示通过skip()跳过指定条数的数据后再通过limit()方法获取指定条数的文档:

db.person.find().skip(1).limit(2)

运行结果如下:

下面演示通过sort()对年龄做排序处理并且用limit()限制排序的个数:

db.person.find().limit(3).sort({"age":-1})

运行结果如下:

下面演示通过count()方法获取当前集合有多少个文档(多少条数据):

db.person.find().count()

运行结果如下:

下面演示获取文档中存在某个字段的文档:

db.person.find({"name":{$exists:true}})

运行结果如下:

下面演示通过dictinct()对属性值进行去重:

db.person.distinct("age")

运行结果如下:

最后演示一下自定义查询:

// 这里的this表示person这个集合
db.person.find({$where:"this.age>=42"})

运行结果如下:

下面演示自定义查询要同时满足多个条件时的用法:

db.person.find({$where:"this.age>=40 && this. Country=='魏国'"})

运行结果如下:


11、聚合操作

概述:MongoDB 中聚合(aggregate)主要用于处理多个文档(诸如统计平均值,求和等),并返回计算后的数据结果。


11.1、分组和过滤

语法

db.集合名称.aggregate([{管道:{表达式}}])

11.1.1、管道命令之$group

概述:$group 是所有聚合命令中用的最多的一个命令,用于将集合中的文档分组,可用于统计结果。

示例

db.stu.aggregate({$group:{_id:"$country",// 这里的counter是随便取的一个变量名counter:{$sum:1}}}
)

注意

  • db.集合名.aggregate 是语法,所有的管道命令都需要写在其中;
  • _id 表示分组的依据,按照哪个字段进行分组,例如:使用$gender表示选择gender字段进行分组;
  • $sum:1 表示把每条数据作为1进行统计,统计的是该分组下面数据的条数。

11.1.2、管道命令之$match

概述:$match 用于进行数据的过滤,是在能够在聚合操作中使用的命令,和 find 区别在于$match 操作可以把结果交给下一个管道处理,而 find 不行。

示例:查询年龄大于20的魏国的人数。

db.person.aggregate([{$match:{age:{$gt:20}}},{$group:{_id:"$country",counter:{$sum:1}}}])

11.1.3、常用表达式

语法

表达式:'$列名'

常用表达式

  • $sum: 计算总和, $sum:1 表示以⼀倍计数
  • $avg: 计算平均值
  • $min: 获取最⼩值
  • $max: 获取最⼤值
  • $push: 在结果⽂档中插⼊值到⼀个数组中

实操:通过本实操掌握分组和过滤的用法。

首先尝试利用管道命令$group对person集合中的country字段进行分组,并且统计每个分组有多少个文档:

db.person.aggregate([{    $group : // 分组中每多一条数据,number就会加1{"_id":"$country" , "number":{$sum:1}}}]
)

运行结果如下:

接下来对上面的程序做升级,要求对country分组后,每个分组中还要包含所有被包含的name属性值:

db.person.aggregate([{$group:{"_id":"$country","names":{$push:"$name"},"number_country":{$sum:1}}}])

运行结果如下:

下面再次对上面的程序做升级,在分组前先过滤出所有年龄大于20的文档,然后再对过滤出的文档做分组处理:

db.person.aggregate([{$match:{age:{$gt:20}}},{$group:{"_id":"$country","names":{$push:"$name"},"number_persons":{$sum:1}}}
])

运行结果如下:

总结

// 单个聚合操作
db.集合名.aggregate(管道命令:{聚合关键字 : info})// 多个聚合操作
db.集合名.aggregate([管道命令1:{聚合关键字:info},管道命令2:{聚合关键字:info},...])


11.2、排序与分页

11.2.1、管道命令之$sort

概述:$sort 用于将输入的文档排序后输出,1表示升序排序,-1表示降序排序。

示例

// 查询人物,按照年龄升序
db.person.aggregate([{$sort:{age:1}}])// 查询每个国家的人数,并排序
db.person.aggregate([{$group:{_id:"$country",counter:{$sum:1}}},{$sort:{counter:-1}}
])

11.2.2、管道命令之 $skip 和 $limit

概述:$limit用于限制返回数据的条数,$skip用于跳过指定的文档数,并返回剩下的文档数。

注意:同时使用 $limit 和 $skip 时先使用 $skip 再使用 $limit。

示例

// 查询2条信息
db.person.aggregate([{$limit:2}
])// 查询从第三条开始的信息
db.person.aggregate([{$skip:3}
])// 查询每个国家的人数,按照人数升序,返回第二条数据
db.person.aggregate([{$group:{_id:"$country",counter:{$sum:1}}},{$sort:{counter:-1}},{$skip:1},{$limit:1}
])

11.2.3、管道命令之$project

概述:$project用于修改文档的输入输出结构,字段值0表示不显示,字段值1表示显示。

示例

// 查询人物的姓名、年龄,不显示ID
db.person.aggregate([{$project:{_id:0,name:1,age:1}}])// 查询每个国家的人数,只显示数量
db.person.aggregate([{$group:{_id:"$country",counter:{$sum:1}}},{$project:{_id:0,counter:1}}])

注意

  • _id 与其他字段共同设置时,0只能设置在 _id 上;
  • 设置字段时,除了 _id 字段,其他默认取反。

实操:通过本实操掌握mongo中排序与分页的操作。

首先尝试 $sort 的用法:

// 对person集合中age字段做降序排序
db.person.aggregate([{$sort:{age:-1}}])

运行结果如下:

下面对country进行分组,并统计每个contry的人数,最后通过人数做降序输出:

db.person.aggregate([{$group:{"_id":"$country","number_man":{$sum:1}}},{$sort:{number_man:-1}}
])

运行结果如下:

下面演示聚合分页,也是对上面的程序做升级:

db.person.aggregate([{$group:{"_id":"$country","num_person":{$sum:1}}},{$sort:{num_person:-1}},{$skip:1},{$limit:1}
])

运行结果如下:

下面演示 $project 控制文档输出:

db.person.aggregate([{$group:{"_id":"$country","num_person":{$sum:1},"age_avg":{$avg:"$age"}}},{$sort:{num_person:-1}},{$project:{num_person:1,age_avg:1}}  // 注意:不要同时设置0和1,否则会报错,但是_id设置为0,其它属性设置为1是被允许的
])

运行结果如下:

最后演示一下 $project 的特殊用法:

db.person.aggregate([{$group:{"_id":"$country","num_person":{$sum:1},"age_avg":{$avg:"$age"}}},{$sort:{num_person:-1}},// 注意:当设置某部分字段的显示方式后,没有指定的默认取反(例如这里将_id设置为不显示,num_person和age_avg没有指定,它们默认不显示,取反后就是显示){$project:{_id:0}}
])

运行结果如下:


12、索引

12.1、索引的基本用法

概述:索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录,这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时。

创建索引的语法

db.集合名.createIndex(keys, options)

提示:语法中 Key 值为要创建的索引字段,1 为指定按升序创建索引,如果想按降序来创建索引指定为 -1 即可。

注意

  • 在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex(),之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名
  • MongoDB默认所有的集合在_id字段上有一个索引。

示例

db.person.createIndex({"name":1})

查看索引的语法

// 默认情况下_id是集合的索引
db.集合名.getIndexes()

删除索引的语法

db.集合名.dropIndex({'索引名称':1})

实操:通过本实操掌握mongo如何创建,查看和删除索引。

首先查看当前person集合中有哪些索引:

// 查看索引
db.person.getIndexes()

运行结果如下:

然后新建一个索引,然后再查看索引:

// 创建新的索引
db.person.createIndex({"name":1})
// 再次查看索引
db.person.getIndexes()

运行结果如下:

下面删除新建的索引,然后再查看索引:

// 删除新建的索引
db.person.dropIndex({"name":1})
// 再次查看索引
db.person.getIndexes()

运行结果如下:

接下来我们尝试验证一下索引是否能提高查询效率,首先准备若干条数据:

for(i=0;i<120000;i++){db.index01.insert({"name":"muxikeqi"+i,"exp":i})
};

查看当前数据集有多少条数据:

db.index01.find().count()

运行结果如下:

获取正常检索muxikeqi99999所消耗的时间:

db.index01.find({"name":"muxikeqi99999"}).explain("executionStats")

运行结果如下,可知查找花费了37ms:

接下来为name属性添加索引并检索:

db.index01.createIndex({"name":1})
db.index01.find({"name":"muxikeqi99999"}).explain("executionStats")

运行结果如下,可知查询花费了0ms:

总结:索引能极大地提高查询速度,数据量越大越需要使用索引。


12.2、唯一索引与复合索引

12.2.1、唯一索引

概述:在默认情况下mongdb的索引的值是可以相同的,创建唯一索引之后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据,但是创建索引仅仅能够提高查询速度,同时降低数据库的插入速度。

语法

db.集合名.createIndex({"字段名":1}, {"unique": true})

基操:利用唯一索引进行数据去重(根据唯一索引指定的字段的值,如果相同,则无法插入数据)

db.person.createIndex({"name":1}, {"unique": true})
db.person.insert({name: 'test10000'})


12.2.2、复合索引

概述:在进行数据去重的时候,可能用多个字段来做数据的唯一性,这个时候可以考虑建立复合索引来实现。

语法

db.collection_name.createIndex({字段1:1,字段2:1})

注意点

  • 根据需要选择是否需要建立唯一索引

  • 索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响

  • 数据量巨大并且数据库的读出操作非常频繁的时候才需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度

实操:通过本实操掌握唯一索引与复合索引的创建。

在创建唯一索引之前,需要提前将index01集合中为name字段添加的索引删除,然后再为name添加唯一索引:

db.index01.dropIndex({"name":1})
db.index01.createIndex({"name":1},{'unique': true})

接下来验证唯一索引,添加一个已经存在的数据:

db.index01.insert({"name":"muxikeqi123"})

运行结果如下,很明显唯一索引已经生效了:

或者直接去查看索引验证:

db.index01.getIndexes()

运行结果如下:

下面尝试为name和age字段创建复合索引:

db.index01.createIndex({"name":1,"age":1})

运行结果如下:

最后验证一下复合索引是否创建成功:

db.index01.getIndexes()

运行结果如下:


13、Python操作mongo

官方文档:PyMongo 4.8.0 documentation

13.1、环境安装

概述:在Pycharm中的终端(Alt+F12)中输入如下代码安装pymongo第三方库。

pip install pymongo==4.2.0

运行结果如下:


13.2、使用样例

引入第三方模块

import pymongo

连接、创建客户端

client = pymongo.MongoClient("localhost", 27017)
client = pymongo.MongoClient('mongodb://localhost:27017/')

获取指定数据库person

db = client.person
db = client['person']

获取指定集合movie

collection = db.movie
collection = db['movie']

添加数据

#增加一条
m1={name:'300集',actor:'高总',level:10}
m1_id = movie.insert_one(s1).inserted_id
#增加多条
mids = movie.insert_many([movie1,movie2])

注意:原insert方法也可以实现上面的功能,但是在PyMongo 3.x的版本已经不推荐使用了。

查找数据

  • find() 返回一个生成器对象
  • find_one() 返回一条数据
result = movie.find_one()
result = movie.find_one({'name':'1200集'})
result = movie.find_one({'_id':OjectId('5932a80115c2606a59e8a049')})
result = movie.find_one({level:{'$gt':1}})
results = movie. Find()

比较符号:1

符号含义示例
$lt小于{'age': {'$lt': 20}}
$gt大于{'age': {'$gt': 20}}
$lte小于等于{'age': {'$lte': 20}}
$gte大于等于{'age': {'$gte': 20}}
$ne不等于{'age': {'$ne': 20}}
$in在范围内{'age': {'$in': [20, 23]}}
$nin不在范围内{'age': {'$nin': [20, 23]}}

功能符号

符号含义示例示例含义
$regex匹配正则表达式{'name': {'$regex': '^M.*'}}name以M开头
$exists属性是否存在{'name': {'$exists': True}}name属性存在
$type类型判断{'age': {'$type': 'int'}}age的类型为int
$mod数字模操作{'age': {'$mod': [5, 0]}}年龄模5余0
$text文本查询{'$text': {'$search': 'Mike'}}text类型的属性中包含Mike字符串
$where高级条件查询{'$where': 'obj.fans_count == obj.follows_count'}自身粉丝数等于关注数

获取文档个数

count = movie.count_documents()

排序

results = collection.find().sort('name', pymongo.ASCENDING)

偏移、分页

collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2)

更新

args = {"name": "曹操"}
student.update_one(args, {'$set':{field:value}}})
result = collection.update_many(query, {'$set': {field: value}})

注意:update也可以实现上面的功能,但是在PyMongo 3.x的版本已经不推荐使用了。

删除

result = collection.remove({'name': '300集'}) # 4.2版本不支持
result = collection.delete_one({'name': '300集'})
result = collection.delete_many({'age': {'$lt': 25}})

实操:通过本实操掌握Python操作mongo的用法。

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]# 操作数据
def add_data():"""添加数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])if __name__ == '__main__':add_data()

运行结果如下:

接下来尝试修改已有数据:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]# 操作数据
def add_data():"""添加数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})if __name__ == '__main__':# add_data()update_data()

运行结果如下:

接下来尝试删除集合中的所有文档:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]# 操作数据
def add_data():"""添加数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})if __name__ == '__main__':# add_data()# update_data()delete_data()

运行结果如下:
 

接下来尝试做无参查询操作:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]
# c3中的数据较多,方便做查询
c3 = db1.person# 操作数据
def add_data():"""添加数据insert_one()用于向指定集合中插入一条数据insert_many()用于向指定集合中插入多条数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据update_one用于修改第一个符合条件的文档update_many用于修改所有符合条件的文档"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据delete_one()用于删除第一个符合条件的文档delete_many()用于删除所有符合条件的文档"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})def search_data():"""查询数据find()用于查询所有符合条件的文档find_one()用于查询第一个符合条件的文档"""resp_all = c3.find()for resp in resp_all:print(resp)if __name__ == '__main__':# add_data()# update_data()# delete_data()search_data()

运行结果如下:

接下来尝试操作有参查询:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]
# c3中的数据较多,方便做查询
c3 = db1.person# 操作数据
def add_data():"""添加数据insert_one()用于向指定集合中插入一条数据insert_many()用于向指定集合中插入多条数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据update_one用于修改第一个符合条件的文档update_many用于修改所有符合条件的文档"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据delete_one()用于删除第一个符合条件的文档delete_many()用于删除所有符合条件的文档"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})def search_data():"""查询数据find()用于查询所有符合条件的文档find_one()用于查询第一个符合条件的文档"""resp_all = c3.find()for resp in resp_all:print(resp)def search_data_args():"""查询指定条件的数据"""rsp_all = c3.find({"age":{"$gt":30}})for rsp in rsp_all:print(rsp)if __name__ == '__main__':# add_data()# update_data()# delete_data()# search_data()search_data_args()

运行结果如下:

下面继续对search_data_args()函数做升级,添加排序功能:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]
# c3中的数据较多,方便做查询
c3 = db1.person# 操作数据
def add_data():"""添加数据insert_one()用于向指定集合中插入一条数据insert_many()用于向指定集合中插入多条数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据update_one用于修改第一个符合条件的文档update_many用于修改所有符合条件的文档"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据delete_one()用于删除第一个符合条件的文档delete_many()用于删除所有符合条件的文档"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})def search_data():"""查询数据find()用于查询所有符合条件的文档find_one()用于查询第一个符合条件的文档"""resp_all = c3.find()for resp in resp_all:print(resp)def search_data_args():"""查询指定条件的数据"""rsp_all = c3.find({"age":{"$gt":30}})# 获取的游标对象需要通过遍历获取具体的元素for rsp in rsp_all:print(rsp)def search_data_args_sort():"""查询指定条件的数据并做降序处理"""rsp_all = c3.find({"age": {"$gt": 30}}).sort("age",pymongo.DESCENDING)for rsp in rsp_all:print(rsp)if __name__ == '__main__':# add_data()# update_data()# delete_data()# search_data()# search_data_args()search_data_args_sort()

运行结果如下:

下面尝试对排序后的结果做分页处理:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]
# c3中的数据较多,方便做查询
c3 = db1.person# 操作数据
def add_data():"""添加数据insert_one()用于向指定集合中插入一条数据insert_many()用于向指定集合中插入多条数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据update_one用于修改第一个符合条件的文档update_many用于修改所有符合条件的文档"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据delete_one()用于删除第一个符合条件的文档delete_many()用于删除所有符合条件的文档"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})def search_data():"""查询数据find()用于查询所有符合条件的文档find_one()用于查询第一个符合条件的文档"""resp_all = c3.find()for resp in resp_all:print(resp)def search_data_args():"""查询指定条件的数据"""rsp_all = c3.find({"age":{"$gt":30}})# 获取的游标对象需要通过遍历获取具体的元素for rsp in rsp_all:print(rsp)def search_data_args_sort():"""查询指定条件的数据并做降序处理"""rsp_all = c3.find({"age": {"$gt": 30}}).sort("age",pymongo.DESCENDING)for rsp in rsp_all:print(rsp)def search_data_args_plus():"""查询指定条件的数据并做降序处理,打印时做分页处理"""rsp_all = c3.find({"age": {"$gt": 30}}).sort("age", pymongo.DESCENDING).skip(4).limit(4)for rsp in rsp_all:print(rsp)if __name__ == '__main__':# add_data()# update_data()# delete_data()# search_data()# search_data_args()# search_data_args_sort()search_data_args_plus()

运行结果如下:

最后演示pymongo如何获取集合中所有的数据条数:

# 引入三方模块
import pymongo# 创建连接(默认连接本机)
client = pymongo.MongoClient()# 获取数据库实例(如果指定的数据库实例不存在就自动创建)
db1 = client.Tsinghua
db2 = client['PyMyMongo']# 获取集合(如果指定的集合不存在就自动创建)
c1 = db1.user
c2 = db2["user"]
# c3中的数据较多,方便做查询
c3 = db1.person# 操作数据
def add_data():"""添加数据insert_one()用于向指定集合中插入一条数据insert_many()用于向指定集合中插入多条数据"""data1 = {"name":"张三","age":20,"score":89}data2 = {"name":"李四","age":22,"score":92}c1.insert_one(data1)c1.insert_many([data1,data2])def update_data():"""修改数据update_one用于修改第一个符合条件的文档update_many用于修改所有符合条件的文档"""# 指定要修改的数据args = {"name":"张三"}# c1.update_one(args,{"$set":{"age":30}})c1.update_many(args,{"$set":{"age":40}})def delete_data():"""删除数据delete_one()用于删除第一个符合条件的文档delete_many()用于删除所有符合条件的文档"""# 删除一条指定特征的数据# c1.delete_one({"name":"张三"}}# 删除所有数据c1.delete_many({})def search_data():"""查询数据find()用于查询所有符合条件的文档find_one()用于查询第一个符合条件的文档"""resp_all = c3.find()for resp in resp_all:print(resp)def search_data_args():"""查询指定条件的数据"""rsp_all = c3.find({"age":{"$gt":30}})# 获取的游标对象需要通过遍历获取具体的元素for rsp in rsp_all:print(rsp)def search_data_args_sort():"""查询指定条件的数据并做降序处理"""rsp_all = c3.find({"age": {"$gt": 30}}).sort("age",pymongo.DESCENDING)for rsp in rsp_all:print(rsp)def search_data_args_plus():"""查询指定条件的数据并做降序处理,打印时做分页处理"""rsp_all = c3.find({"age": {"$gt": 30}}).sort("age", pymongo.DESCENDING).skip(4).limit(4)for rsp in rsp_all:print(rsp)def count_data():"""获取当前集合中文档的总数"""# 注意:count_documents()方法也可以统计指定条件的文档个数count = c3.count_documents({})print(f"c3中文档的总数为:{count}")if __name__ == '__main__':# add_data()# update_data()# delete_data()# search_data()# search_data_args()# search_data_args_sort()# search_data_args_plus()count_data()

运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/394988.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python爬虫学习记录-请求模块urllib3

&#xff08;文章内容仅作学习交流使用&#xff09; urllib3是一个功能强大、条理清晰&#xff0c;用于HTTP客户端的第三方模块 urllib3-发送网络请求 使用urllib3发送网络请求时&#xff0c;需要先创建PoolManager对象&#xff0c;并使用该对象的request方法发送请求&#…

[Spring] Spring AOP

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

Qt实现类似淘宝商品看板的界面,带有循环翻页以及点击某页跳转的功能

效果如下&#xff1a; #ifndef ModelDashboardGroup_h__ #define ModelDashboardGroup_h__#include <QGridLayout> #include <QLabel> #include <QPushButton> #include <QWidget>#include <QLabel> #include <QWidget> #include <QMou…

扩展【从0制作自己的ros导航小车】C++_ROS_QT5联合编译,简单界面为ROS开发增添交互

从0制作自己的ros导航小车 前言一、环境搭建二、联合编译三、测试 前言 前面已经实现了导航功能&#xff0c;对于之后的一些开发&#xff0c;有交互能力是比较重要的&#xff0c;比如小车上连接一块屏幕&#xff0c;通过屏幕来选择模式&#xff0c;可视化等等。QT是不错的选择…

LVS是什么?以及LVS-NAT以及DR模式实验

目录 NAT LVS LVS集群的类型&#xff1a; LVS-NAT模式实验 环境准备&#xff1a; 实验步骤&#xff1a; LVS-DR模式实验 题目&#xff1a; 环境准备&#xff1a; 实验步骤&#xff1a; LVS-防火墙标签解决轮询调度问题 环境准备&#xff1a; 实验步骤&#xff1…

智界S7 小鹏P7 G3 G3i P5 G9 P7i G6 X9维修手册和电路图线路图接线资料更新

汽修帮手资料库提供各大厂家车型维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表位置等&#xff0c;并长期保持高频率资料更新&#xff01; 覆盖车型2020-2024年智界S7 小鹏…

在VScode中导入conda环境的记录【原创】

今天在vscode编辑器中运行一个python代码&#xff0c;发现终端可以运行&#xff0c;但是编辑器中点击Run会显示缺包&#xff0c;但是python包明明是有的&#xff0c;在自己的conda环境中。后来发现&#xff0c;是vscode没有发现我自己创建的conda环境&#xff0c;在vscode中导入…

51单片机个人学习笔记16(红外遥控)

前言 本篇文章属于STC89C52单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 [1-1] 课程简介_哔哩…

Java封装原生ES

文章目录 &#x1f31e; Sun Frame&#xff1a;SpringBoot 的轻量级开发框架&#xff08;个人开源项目推荐&#xff09;&#x1f31f; 亮点功能&#x1f4e6; spring cloud模块概览常用工具 &#x1f517; 更多信息1.spring-data-es操作ES1.引入依赖2.application.yml配置uris3…

高频焊接设备配电系统无源滤波系统的设计

1、高频焊机系统谐波状况简介 变压器容量&#xff1a;S11-M-1600/10KVA&#xff08;105%&#xff09;/0.4KV 短路阻抗&#xff1a;3.9% 谐波负载情况&#xff1a;一台600KW高频焊接设备 型号&#xff1a;GGP600-0.3-HC 输入电压&#xff1a;380V 输出电压&#xff1a;0…

【Python机器学习】回归——示例:预测乐高玩具套装的价格

用回归法预测乐高套装价格的基本步骤&#xff1a; 1、收集数据&#xff1a;用Google Shopping的API收集到的数据 2、准备数据&#xff1a;从返回的JSON数据中抽取价格 3、分析算法&#xff1a;可视化并观察数据 4、训练算法&#xff1a;构建不同的模型&#xff0c;采用逐步线性…

操作ArkTS页面跳转及路由相关心得

本文为JS老狗原创。 当前端不得不关注的点&#xff1a;路由&#xff0c;今天聊一聊鸿蒙相关的一点心得。 总体上套路不意外&#xff0c;基本就是&#xff08;尤其是Web&#xff09;前端那些事&#xff1a;维护路由表、跳转带参数、历史堆栈操作&#xff0c;等等。 历史原因&…

设计模式20-备忘录模式

设计模式20-备忘录 动机定义与结构定义结构 C代码推导优缺点应用场景总结备忘录模式和序列化备忘录模式1. **动机**2. **实现方式**3. **应用场景**4. **优点**5. **缺点** 序列化1. **动机**2. **实现方式**3. **应用场景**4. **优点**5. **缺点** 对比总结 动机 在软件构建过…

云服务器和物理服务器的优缺点对比

云服务器优点在于灵活性强、成本效益高、易于扩展且支持全球化部署&#xff1b;缺点则包括安全性与可控性相对较弱&#xff0c;性能可能受限&#xff0c;以及存在服务中断风险。物理服务器则以其高性能、高稳定性、强安全性和完全可控性著称&#xff0c;但成本较高、扩展性受限…

鸿蒙OS ArkTS 省市县级联选择框,封装组件

背景&#xff1a; 公司现在要开发纯血鸿蒙版本APP&#xff0c;我被抽调过来做点功能。现在要做一个省市县级联选择框&#xff0c;并且要封装为组件&#xff0c;供其他页面模块使用。 效果图&#xff1a; 难点&#xff1a; 1. 现在官方文档上只是查到了TextPicker组件是可以做…

Vue3+setup使用vuemap/vue-amap实现地图相关操作

首先要下载依赖并且引入 npm安装 // 安装核心库 npm install vuemap/vue-amap --save// 安装loca库 npm install vuemap/vue-amap-loca --save// 安装扩展库 npm install vuemap/vue-amap-extra --save cdn <script src"https://cdn.jsdelivr.net/npm/vuemap/vue-a…

软件测试需要具备的基础知识【功能测试】---前端知识(三)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 为了更好的学习软件测试的相关技能&#xff0c;需要具备一定的基础知识。需要学习的基础知识包括&#xff1a; 1、计算机基础 2、前端知识 3、后端知识 4、软件测试理论 后期分四篇文章进行编写&#xff0c;这是第二篇 …

使用es-hadoop同步hive和es之间数据

&#x1f4bb;近期在华为云连接es时的时候发现不能输入账号密码&#xff0c;后面联系华为工程师了解到&#xff0c;华为云默认是非安全模式&#xff0c;即不需要输入账号密码。 如果对你有所帮助&#xff0c;欢迎点赞收藏关注不迷路哦&#x1f493; 目录 使用es-hadoop同步h…

AI时代,我们还可以做什么?

最近看了本书&#xff0c;书名叫做《拐点&#xff1a;站在 AI 颠覆世界的前夜》&#xff0c;作者是万维钢。 本想着看完后&#xff0c;就能掌握一整套 AI 技巧&#xff0c;结果——竟然学了很多道理。 这本书讨论了以下话题&#xff1a; 我们该怎么理解这个 AI 大时代的哲学&am…

国产数据库备份恢复实现

数据库备份恢复是数据库高可用的基本能力&#xff0c;如何通过备份数据快速高效的恢复业务并且满足不同场景下的恢复需求&#xff0c;是各数据库厂商需要关注的要点。本文将介绍几种国产数据库的备份恢复功能&#xff0c;以加深了解。 1、数据库备份恢复方案 数据库备份是生产…