MongoDB从零开始详细教程(超详细讲解)

news/2024/11/20 23:19:40/

image-20210415004036406

目录

  • 一、简介
    • 1. 简单介绍
    • 2. 业务应用场景
    • 3. 什么时候选择MongoDB
    • 4. 体系机构
    • 5. 数据类型
    • 6. 特点
  • 二、Windows安装&启动&连接
    • 1. 下载压缩包
    • 2. 解压
    • 3. 安装服务
    • 4. 启动服务
    • 5. shell连接登录&退出
    • 6. Compass图形化连接登录
  • 三、Linux安装&启动&连接
    • 1. 下载压缩包
    • 2. 上传到服务器&解压
    • 3. 创建数据/日志存放目录
    • 4. 启动服务
    • 5. 登录
    • 6. Compass图形化连接登录
  • 四、基本常用命令
    • 1. 数据库相关
    • 2. 集合相关
  • 五、CURD
    • 增:插入文档
    • 删:删除文档
    • 改:修改文档
    • 查:查询文档
  • 六、排序&分页
    • 排序
    • 分页
  • 七、聚合查询
    • 1. 语法
    • 2. 测试
  • 八、索引
    • 1. 简介
    • 2. 语法
    • 3. 练习
    • 4. 分析索引(explain)
    • 5. 选择规则
  • 九、权限机制
    • 创建账号语法
    • 开启验证模式
      • 1. 添加超级管理员账号
      • 2. 卸载服务
      • 3. 安装需要身份验证的服务
      • 4. 启动服务
      • 5. 登录测试
      • 6. 通过超级管理员账号登录
    • 练习
  • 十、备份还原
    • 下载MongoDB数据库工具
    • 备份数据库mongodump
    • 还原数据库mongorestore
  • 十一、实战可视化管理Robo 3T
    • 1. 下载安装Robo 3T
    • 2. 使用Robo 3T
  • 十二、mongoose
    • 1. 简介
    • 2. 安装
    • 3. CURD语法
    • 4. 测试
  • 十三、接口
    • 1. 简介
    • 2. 接口开发规范(Restful API)
    • 3. 接口测试工具Postman
      • 1. 简介
      • 2. 下载安装
      • 3. 使用
  • 十四、express框架教学系统学生模块接口开发
    • 1. express快速入门
    • 2. 教学系统学生模块接口开发
      • 1. 安装模块依赖
      • 2 expree框架搭建,定义路由
      • 3. mongoose模块操作数据库
      • 3. 编写路由处理方法
      • 4. 测试
    • 3. 接口文档开发apiDoc
      • 1. 简介
      • 2. 使用

参考课程

  • https://www.bilibili.com/video/BV1xz4y1X7cE?p=30&t=594
  • https://www.bilibili.com/video/BV1bJ411x7mq?p=7&t=88

一、简介

1. 简单介绍

  • MongoDB是一个基于分布式文件存储的数据库
  • 由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。
  • MongoDB是一个介于关系数据库非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
  • 它支持的数据结构非常松散,是类似jsonbson格式,因此可以存储比较复杂的数据类型。
  • Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引

image-20201225001713452


2. 业务应用场景

传统的关系型数据库(如MySQL),在数据操作的三高需求以及应对Web2.0的网站需求面前,显得力不从心,而 MongoDB可应对“三高“需求

  • High performance:对数据库高并发读写的需求

  • Huge Storage:对海量数据的高效率存储和访问的需求

  • High Scalability && High Availability:对数据库的高可扩展性和高可用性的需求

具体应用场景

  1. 社交场景,使用 MongoDB存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。
  2. 游戏场景,使用 MongoDB存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。
  3. 物流场景,使用 MongoDB存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来
  4. 物联网场景,使用 MongoDB存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。
  5. 视频直播,使用 MongoDB存储用户信息、点赞互动信息等。

这些应用场景中,数据操作方面的共同特点是:

(1)数据量大

(2)写入操作频繁(读写都很频繁)

(3)价值较低的数据,对事务性要求不高

对于这样的数据,我们更适合使用 MongoDB来实现数据的存储。


3. 什么时候选择MongoDB

  • 应用不需要事务及复杂join支持

  • 新应用,需求会变,数据模型无法确定,想快速迭代开发

  • 应用需要2000-3000以上的读写QPS(更高也可以)

  • 应用需要TB甚至PB级别数据存储

  • 应用要求存储的数据不丢失

  • 应用需要99.999%高可用

  • 应用需要大量的地理位置查询、文本查

相对MySQL,在以上以用场景可以以更低的成本解决问题(包括学习、开发、运维等成本)


4. 体系机构

image

image


5. 数据类型

MongoDB的最小存储单位就是文档document对象。文档document对象对应于关系型数据库的行。数据在MongoDB中以BSON(Binary-JSON)文档的格式存储在磁盘上。

BSON(Binary Serialized Document Format)是一种类json的一种二进制形式的存储格式,简称 Binary JSON;BSON和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和Bin Data类型。

BSON采用了类似于C语言结构体的名称、对表示方法,支持内嵌的文档对象和数组对象,具有轻量性、可遍历性、高效性的三个特点,可以有效描述非结构化数据和结构化数据。这种格式的优点是灵活性高,但它的缺点是空间利用率不是很理想。

BSON中,除了基本JSON类型: string,integer,boolean,double,null,array和object,mongo还使用了特殊的数据类型。这些类型包括 date, object id, binary data, regular expression和code。每一个驱动都以特定语言的方式实现了这些类型,查看你的驱动的文档来获取详细信息

BSON数据类型参考列表:
image
提示
shell默认使用64位浮点型数值。{“x”:3.14或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或 NumberLong(8字节符号整数),{“x”:NumberInt(“3” ){“x”:NumberLong(“3”)}


6. 特点

1. 高性能
MongoDB提供高性能的数据持久性。特别是,

对嵌入式数据模型的支持减少了数据库系统上I/O活动。

索引支持更快的查询,并且可以包含来自嵌入式文档和数组的键。(文本索引解决搜索的需求、TTL索引解决历史数据自动过期的需求、地理位置索引可用于构建各种O2O应用)

mmapv1、 wiredtiger、 mongorocks( rocks)、 In-memory等多引擎支持满足各种场景需求

Gridfs解决文件存储的需求

2. 高可用性
MongoDB的复制工具称为副本集( replica set),它可提供自动故障转移和数据冗余

3. 高扩展性
MongoDB提供了水平可扩展性作为其核心功能的一部分。

分片将数据分布在一组集群的机器上。(海量数据存储,服务能力水平扩展)

从3.4开始,MoηgoDB支持基于片键创建数据区域。在一个平衡的集群中, MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片。

4. 丰富的查询支持
MongoDB支持丰富的査询语言,支持读和写操作(CRUD),比如数据聚合、文本搜索和地理空间查询等

5. 其他特点

如无模式(动态模式)、灵活的文档模型



二、Windows安装&启动&连接

1. 下载压缩包

下载地址:https://www.mongodb.com/try/download/community

这里以zip的格式进行下载
image-20201219222856046
附加:mongodb的命名格式: x.y.z

- y为奇数表示当前版本为开发版,如:1.5.2、4.1.13
- y为偶数表示当前版本为稳定版,如:1.6.3、4.0.10
- z为修正版本号,越大越好

2. 解压

下载完成后得到压缩包,解压;其中的bin目录就存放着mongodb相关的命令
image-20201219223125103


3. 安装服务

首先要在安装目录里创建两个目录:

  • 数据目录:data
  • 日志目录:logs

image-20201219223321905
然后以管理员模式,切换到安装目录下的bin目录运行以下格式命令来指定mongdb的数据及日志目录

mongod --install --dbpath 数据目录 --logpath 日志目录\日志名称 

这里为:

mongod --install --dbpath D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data --logpath D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\logs\mongodb.log

image-20201219223752457
没有任何报错和提示,则代表MongoDB服务创建成功

我们可以进行验证,win+r输入services.msc
image-20201219223926325
看到MongoDB服务即成功


4. 启动服务

输入以下命令启动服务

net start mongodb

image-20201219224027011

5. shell连接登录&退出

输入以下命令进行登录与退出

#登录
mongo
mongo --host=localhost --port=27017#退出
exit	


相关语法:

mongod --install --dbpath 数据目录 --logpath 日志目录\日志名称	#创建服务
mongod --remove											  #卸载服务		
net start mongodb	#启动服务
net stop mongodb	#关闭服务

6. Compass图形化连接登录

MongoDB的GUI。直观地浏览您的数据。在几秒钟内运行查询。借助完整的CRUD功能与您的数据进行交互。查看和优化您的查询性能。在Linux,Mac或Windows上可用。Compass使您能够做出更明智的索引,文档验证等决策。

image-20210222191236485

下载地址:https://www.mongodb.com/try/download/compass
image-20210222191353792
点击Download下载即可,下载完成后得到压缩包
image-20210222191636947
解压,可以看到MongoDBCompass.exe
image-20210222191731768
双击运行,直接Next,最后Get Stated,默认选项即可
image-20210222191823007
然后直接点击CONNECT就会连接本地的数据库localhost:27017
image-20210222192209942
可以看到所有的数据库及相关信息
image-20210222192314982



三、Linux安装&启动&连接

环境:阿里云服务器Centos7

1. 下载压缩包

下载地址:https://www.mongodb.com/try/download/community

选择对应的系统版本(这里为Centos7),以tgz的格式进行下载
image-20210222193408915


2. 上传到服务器&解压

将下载得到的压缩包上传到服务器,这里使用xftp工具进行上传
image-20210222204535567
然后解压

tar -zxvf mongodb-linux-x86_64-rhel70-4.4.4.gz

然后将解压后的文件移至usr/local/mongodb目录下,这是我们一般存放文件的位置

mv mongodb-linux-x86_64-rhel70-4.4.4 /usr/local/mongodb

3. 创建数据/日志存放目录

mkdir -p /usr/local/mongodb/data /usr/local/mongodb/logs

image-20210222205638083


4. 启动服务

/usr/local/mongodb/bin/mongod --dbpath=/usr/local/mongodb/data/ --logpath=/usr/local/mongodb/logs/mongodb.log --logappend --port=27017 --fork

image-20210222205649708


5. 登录

# 登录
/usr/local/mongodb/bin/mongo# 退出
exit

image-20210222205741915


6. Compass图形化连接登录

利用Compass进行连接,Hostname为服务器的公网IP,其他默认

image-20210222211447960

连接失败的原因

1. 未打开安全组策略

暴露给外部的端口需要打开对应的安全组设置
image-20210222212449335

2. 防火墙开放端口未设置

首先查看防火墙是否开启,结果为not running表示未开启,则不是防火墙的问题,跳过

# 查看防火墙是否开启
firewall-cmd --state

如果显示running,则继续排查,查看防火墙开放的端口

# 查看防火墙所开放的端口
firewall-cmd --list-ports[root@zsr ~]# firewall-cmd --list-ports
20/tcp 21/tcp 22/tcp 80/tcp 8888/tcp 39000-40000/tcp 3306/tcp 3306/udp 8080/tcp 8080/udp 3355/tcp

也可以用firewall-cmd --list-all查看防火墙的详细信息
image-20210129122719570
我这里的问题就是防火墙未开放27017端口,所以要开放防火墙的对外暴露的端口

# 开放90端口(--premanent表示永久添加)
firewall-cmd --permanent --add-port=27017/tcp# 重启防火墙(修改配置后要重启防火墙)
firewall-cmd --reload

添加完成后再次查看就可以看到27017端口被开放
image-20210222211731880



四、基本常用命令

1. 数据库相关

# 查看所有数据库
show databases# 选择数据库(如果数据库不存在,不会报错;会隐式创建:当后期该数据库有数据时自动创建)
use 数据库名# 删除数据库(先选中数据库)
db.dropDatabase()

2. 集合相关

# 查看所有集合
show collections# 创建集合(插入数据会隐式创建)
db.createCollection('集合名')# 删除集合
db.集合名.drop()


五、CURD

增:插入文档

db.集合名.insert(json数据)
  • 集合存在则直接插入数据,不存在则隐式创建集合并插入数据

  • json数据格式要求key得加"",但这里为了方便查看,对象的key统一不加"";查看集合数据时系统会自动给key加""

  • mongodb会自动给每条数据创建全球唯一的_id键(我们也可以自定义_id的值,只要给插入的json数据增加_id键即可覆盖,但是不推荐这样做)

    img

测试

插入一条数据

image-20210222235515711

一次插入多条数据并指定_id

image-20210223000501376

利用for循环插入数据

for(var i=1;i<10;i++){db.student.insert({name:"a"+i,age:i})
}

image-20210223001002189


删:删除文档

db.集合名.remove(条件 [,是否删除一条])# 是否删除一条
- false删除多条,即全部删除(默认)
- true删除一条

image-20210223132359528


改:修改文档

db.集合名.update(条件, 新数据 [,是否新增, 是否修改多条])# 新数据
- 默认是对原数据进行替换
- 若要进行修改,格式为 {修改器:{key:value}}# 是否新增
- 条件匹配不到数据时是否插入: true插入,false不插入(默认)# 是否修改多条
- 条件匹配成功的数据是否都修改: true都修改,false只修改一条(默认)
修改器作用
$inc递增
$rename重命名列
$set修改列值
$unset删除列

准备工作:插入十条数据

for(var i=1;i<=10;i++){db.people.insert({name:"zsr"+i,age:i})
}

image-20210223100253776

将{name:“zsr1”}更改为{name:“zsr2”}

db.people.update({name:"zsr1"},{name:"zsr2"})

发现问题:默认不是修改而是替换
image-20210223101214051

解决问题:使用修改器将{name:“zsr3”}更改为{name:“zsr3333”}

db.people.update({name:"zsr3"},{$set:{name:"zsr3333"}})

image-20210223102308690

给{name:“zsr10”}的年龄增加或减少2岁

# 增加两岁
db.people.update({name:"zsr10"},{$inc:{age:2}})# 减少两岁
db.people.update({name:"zsr10"},{$inc:{age:-2}})

image-20210223130651064

一次写多个修改器

首先插入一条数据

db.people.insert({username:"gcc",age:20,sex:"女",address:"unknown"})

任务:修改gcc的username为bareth,age+11,sex字段重命名为sexuality,删除address字段

db.people.update({username:"gcc"},{$set:{username:"bareth"},$inc:{age:11},$rename:{sex:"sexuality"},$unset:{address:true}
})

image-20210223131538737


查:查询文档

db.集合名.find(条件 [,查询的列])
db.集合名.find(条件 [,查询的列]).pretty()	#格式化查看# 条件
- 查询所有数据	{}或不写
- 查询指定要求数据	{key:value}{key:{运算符:value}}# 查询的列(可选参数)
- 不写则查询全部列
- {key:1}	只显示key列
- {key:0}	除了key列都显示
- 注意:_id列都会存在
运算符作用
$gt大于
$gte大于等于
$lt小于
$lte小于等于
$ne不等于
$inin
$ninnot in

查询指定列的所有数据

image-20210223093306196

查询指定条件的数据

image-20210223094819105



六、排序&分页

数据准备

for(var i=1;i<5;i++){db.person.insert({_id:i,name:"p"+i,age:10+i})
}

image-20210301134521650

排序

db.集合名.find().sort(json数据)# json数据(key:value)
- key就是要排序的字段
- value为1表示升序,-1表示降序

按年龄降序排列
image-20210223183828304


分页

db.集合名.find().sort().skip(数字).limit(数字)[.count()]# skip(数字)
- 指定跳过的数量(可选)# limit(数字)
- 限制查询的数量# count()
- 统计数量

测试:
image-20210223184455261

实战:数据库有1~10条数据,每页显示2条,一共5页

skip计算公式: (当前页-1)*每页显示的条数页数 起始 终止 跳过数
1页	1	2	0
2页	3	4	2
3页	5	6	4
4页	7	8	6
5页	9	10	8
# 数据准备
for(var i=1;i<11;i++){db.page.insert({_id:i,name:"p"+i})
}# 分5页,每页2条显示
for(var i=0;i<10;i=i+2){db.page.find().skip(i).limit(2)
}


七、聚合查询

1. 语法

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

常用管道

$group将集合中的文档分组,用于统计结果
$match过滤数据,只输出符合条件的文档
$sort聚合数据进一步排序
$skip跳过指定文档数
$limit限制集合数据返回文档数

常用表达式

$sum总和($num:1同count表示统计)
$avg平均
$min最小值
$max最大值

2. 测试

数据准备:

db.people.insert({_id:1,name:"a",sex:"男",age:21})
db.people.insert({_id:2,name:"b",sex:"男",age:20})
db.people.insert({_id:3,name:"c",sex:"女",age:20})
db.people.insert({_id:4,name:"d",sex:"女",age:18})
db.people.insert({_id:5,name:"e",sex:"男",age:19})

统计男生、女生的总年龄

db.people.aggregate([{$group:{_id:"$sex",age_sum:{$sum:"$age"}}}
])

image-20210223234358509

统计男生女生的总人数

db.people.aggregate([{$group:{_id:"$sex",sum:{$sum:1}}}
])

image-20210223234722079

求学生总数和平均年龄

db.people.aggregate([{$group:{_id:null,total_num:{$sum:1},total_avg:{$avg:"$age"}}}
])

image-20210224103820145

查询男生、女生人数,按人数升序

db.people.aggregate([{$group:{_id:"$sex",rs:{$sum:1}}},{$sort:{rs:1}}
])

image-20210224104707963



八、索引

1. 简介

索引是一种排序好的便于快速查询数据的数据结构,用于帮助数据库高效的查询数据
image-20210224110005650

优点

  • 提高数据查询的效率,降低数据库的IO成本
  • 通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗

缺点

  • 占用磁盘空间
  • 大量索引影响SQL语句的执行效率,因为每次插入和修改数据都要更新索引

2. 语法

创建索引语法

# 创建索引
db.集合名.createIndex(待创建索引的列:方式 [,额外选项])
# 创建复合索引
db.集合名.createIndex({key1:方式,key2:方式} [,额外选项])# 参数说明:
- `待创建索引的列:方式`{key:1}/{key:-1}1表示升序,-1表示降序; 例如{age:1}表示创建age索引并按照升序方法排列
- `额外选项`:设置索引的名称或者唯一索引等设置名称:{name:索引名}唯一索引:{unique:列名}

删除索引语法

# 删除全部索引
db.集合名.dropIndexes()
# 删除指定索引
db.集合名.dropIndex(索引名)

查看索引语法

# 查看索引
db.集合名.getIndexes()

3. 练习

十万条数据准备

# 选择数据库
use test
# 插入100000条数据
for(var i=0;i<100000;i++){db.data.insert({name:"zsr"+i,age:i})
}

image-20210224112318002

创建普通索引

# 给name添加普通升序索引
db.data.createIndex({name:1})

image-20210224112835226

# 给age创建索引并起名age_up
db.data.createIndex({age:1},{name:"age_up"})

image-20210224113629158

删除索引

# 删除name列的索引
db.data.dropIndex("name_1")

image-20210224112949548

创建复合/组合索引:也就是一次给两个字段建立索引

# 给name和age添加组合索引
db.data.createIndex({name:1,age:1})

image-20210224170703739

创建唯一索引

# 删除所有索引
db.data.dropIndexes()# 给name创建唯一索引
db.data.createIndex({name:1},{unique:"name"})

image-20210224171614328


4. 分析索引(explain)

db.集合名.find().explain('executionStats')

我们通过简单的案例来测试索引的好处

  • 不加索引时查询age=500的数据
> db.data.find({age:500}).explain('executionStats')
{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "test.data","indexFilterSet" : false,"parsedQuery" : {"age" : {"$eq" : 500}},"winningPlan" : {"stage" : "COLLSCAN","filter" : {"age" : {"$eq" : 500}},"direction" : "forward"},"rejectedPlans" : [ ]},"executionStats" : {	#执行计划相关统计信息"executionSuccess" : true,	#执行成功的状态"nReturned" : 1,	#返回结果集数目"executionTimeMillis" : 37,	#执行所需要的ms数"totalKeysExamined" : 0,	#索引检查的时间"totalDocsExamined" : 100000,	#检查文档总数"executionStages" : {"stage" : "COLLSCAN",	#索引扫描方式"filter" : {	#过滤条件"age" : {"$eq" : 500}},"nReturned" : 1,	#返回结果集数目"executionTimeMillisEstimate" : 1,	#预估执行时间(ms)"works" : 100002,	#工作单元数,一个查询会被派生为一个小的工作单元"advanced" : 1,	#优先返回的结果数"needTime" : 100000,"needYield" : 0,"saveState" : 100,"restoreState" : 100,"isEOF" : 1,"direction" : "forward",	 "docsExamined" : 100000	#文档检查数目}},"serverInfo" : {"host" : "LAPTOP-8J48VF43","port" : 27017,"version" : "4.4.2","gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e"},"ok" : 1
}
  • 给age添加一个升序索引后
# 给age添加升序索引
> db.data.createIndex({age:1})
{"createdCollectionAutomatically" : false,"numIndexesBefore" : 2,"numIndexesAfter" : 3,"ok" : 1
}
# 性能分析
> db.data.find({age:500}).explain('executionStats')
{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "test.data","indexFilterSet" : false,"parsedQuery" : {"age" : {"$eq" : 500}},"winningPlan" : {"stage" : "FETCH","inputStage" : {"stage" : "IXSCAN","keyPattern" : {"age" : 1},"indexName" : "age_1","isMultiKey" : false,"multiKeyPaths" : {"age" : [ ]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"age" : ["[500.0, 500.0]"]}}},"rejectedPlans" : [ ]},"executionStats" : {	#执行计划相关统计信息"executionSuccess" : true,	#执行成功的状态"nReturned" : 1,	#返回结果集数目"executionTimeMillis" : 1,	#执行所需要的ms数"totalKeysExamined" : 1,	#索引检查的时间"totalDocsExamined" : 1,	#检查文档总数"executionStages" : {"stage" : "FETCH",	#索引扫描方式"nReturned" : 1,	#返回结果集数目"executionTimeMillisEstimate" : 0,	#预估执行时间(ms)"works" : 2,	#工作单元数,一个查询会被派生为一个小的工作单元"advanced" : 1,	#优先返回的结果数"needTime" : 0,"needYield" : 0,"saveState" : 0,"restoreState" : 0,"isEOF" : 1,"docsExamined" : 1,"alreadyHasObj" : 0,"inputStage" : {"stage" : "IXSCAN","nReturned" : 1,"executionTimeMillisEstimate" : 0,"works" : 2,"advanced" : 1,"needTime" : 0,"needYield" : 0,"saveState" : 0,"restoreState" : 0,"isEOF" : 1,"keyPattern" : {"age" : 1},"indexName" : "age_1","isMultiKey" : false,"multiKeyPaths" : {"age" : [ ]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"age" : ["[500.0, 500.0]"]},"keysExamined" : 1,"seeks" : 1,"dupsTested" : 0,"dupsDropped" : 0}}},"serverInfo" : {"host" : "LAPTOP-8J48VF43","port" : 27017,"version" : "4.4.2","gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e"},"ok" : 1
}

三种扫描方式

  • COLLSCAN:全盘扫描
  • INSCAN:索引扫描
  • FETCH:根据索引去检索指定document

5. 选择规则

如何选择合适的列创建索引?

  • 为常做条件、排序、分组的字段建立索引
  • 选择唯一性索引
  • 选择较小的数据列,为较长的字符串使用前缀索引


九、权限机制

安装完Mongodb后,在命令行输入mongo命令即可登录数据库,这肯定是不安全的,我们需要使用权限机制,开启验证模式

创建账号语法

创建账号

db.createUser({"user":"账号","pwd":"密码","roles":[{role:"角色",db:"所属数据库"}]
})

角色种类

  • 超级用户角色:root
  • 数据库用户角色:readreadWrite
  • 数据库管理角色:dbAdminuserAdmin
  • 集群管理角色: clusterAdminclusterManagerclusterMonitorhostManager
  • 备份恢复角色: backuprestore
  • 所有数据库角色: readAnyDatabasereadWriteAnyDatabaseuserAdminAnyDatabasedbAdminAnyDatabase

角色说明

  • root:只在admin数据库中可用。超级账号,超级权限;
  • read:允许用户读取指定数据库;
  • readWrite:允许用户读写指定数据库

开启验证模式

验证模式:值用户需要输入账号密码才能登录使用

1. 添加超级管理员账号

# 必须使用admin数据库
use admin# 创建超级用户
db.createUser({"user":"zsr","pwd":"123456","roles":[{role:"root",db:"admin"}]
})

image-20210224183401582
然后查看admin数据库中的集合system.users可以查看详细信息
image-20210224183540573

2. 卸载服务

首先exit退出登录,然后以管理员模式打开终端输入如下命令卸载服务

# 卸载服务
mongod --remove

image-20210224191707674

3. 安装需要身份验证的服务

mongod --install --dbpath 数据目录 --logpath 日志目录\日志名称 --auth

这里为:

mongod --install --dbpath D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data --logpath D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\logs\mongodb-zsr.log --auth

4. 启动服务

net start mongodb

image-20210224192124655

5. 登录测试

输入mongo命令登录,可以发现不再显示警告,且查看数据库看不到,这是因为还没有身份验证,没有通过账号登录

image-20210224192324211

6. 通过超级管理员账号登录

# 方法一
mongo 服务器ip地址:端口号/数据库 -u 用户名 -p 密码

image-20210224193541511

# 方法二
mongo	#先登录
use admin	#选择数据库
db.auth(用户名,密码)

image-20210224205733706


练习

  • 需求

添加用户shop1可以读shop数据库

添加用户shop2可以读写shop数据库

注意:必须在对应的数据库中创建用户

  • 准备:创建测试数据
use shop
for(var i=1;i<=10;i++){db.goods.insert({name:"goods"+i,price:i})
}

image-20210224210448805

  • 添加用户并设置权限
use shop# 创建shop1用户
db.createUser({"user":"shop1","pwd":"123456","roles":[{role:"read",db:"shop"}]
})# 创建shop2用户
db.createUser({"user":"shop2","pwd":"123456","roles":[{role:"readWrite",db:"shop"}]
})

image-20210224211009044

  • 验证:shop1可读,shop2可读可写
# 验证shop1可读
C:\WINDOWS\system32>mongo localhost:27017/shop -u shop1 -p 123456
MongoDB shell version v4.4.2
connecting to: mongodb://localhost:27017/shop?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("727ada5f-985f-4858-bb30-523d1777fa3a") }
MongoDB server version: 4.4.2
> show dbs
shop  0.000GB
> db.goods.find()	#可读
{ "_id" : ObjectId("60364ec9fd9e42c81a76f431"), "name" : "goods1", "price" : 1 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f432"), "name" : "goods2", "price" : 2 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f433"), "name" : "goods3", "price" : 3 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f434"), "name" : "goods4", "price" : 4 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f435"), "name" : "goods5", "price" : 5 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f436"), "name" : "goods6", "price" : 6 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f437"), "name" : "goods7", "price" : 7 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f438"), "name" : "goods8", "price" : 8 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f439"), "name" : "goods9", "price" : 9 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f43a"), "name" : "goods10", "price" : 10 }
> db.goods.insert({name:"zsr"})	#不可写
WriteCommandError({"ok" : 0,"errmsg" : "not authorized on shop to execute command { insert: \"goods\", ordered: true, lsid: { id: UUID(\"727ada5f-985f-4858-bb30-523d1777fa3a\") }, $db: \"shop\" }","code" : 13,"codeName" : "Unauthorized"
})# 验证shop2可读可写
C:\WINDOWS\system32>mongo localhost:27017/shop -u shop2 -p 123456
MongoDB shell version v4.4.2
connecting to: mongodb://localhost:27017/shop?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("1fbca023-aeb3-4514-b2e4-700934000cc9") }
MongoDB server version: 4.4.2
> db.goods.find()	#可读
{ "_id" : ObjectId("60364ec9fd9e42c81a76f431"), "name" : "goods1", "price" : 1 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f432"), "name" : "goods2", "price" : 2 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f433"), "name" : "goods3", "price" : 3 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f434"), "name" : "goods4", "price" : 4 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f435"), "name" : "goods5", "price" : 5 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f436"), "name" : "goods6", "price" : 6 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f437"), "name" : "goods7", "price" : 7 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f438"), "name" : "goods8", "price" : 8 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f439"), "name" : "goods9", "price" : 9 }
{ "_id" : ObjectId("60364ec9fd9e42c81a76f43a"), "name" : "goods10", "price" : 10 }
> db.goods.insert({name:"zsr"})	可写
WriteResult({ "nInserted" : 1 })


十、备份还原

下载MongoDB数据库工具

进行备份还原之前,首先要下载相关的工具

MongoDB Database Tools:https://www.mongodb.com/try/download/database-tools

MongoDB数据库工具是用于处理MongoDB部署的命令行实用程序的集合。这些工具独立于MongoDB Server计划发布,使您能够获得更频繁的更新,并在新功能可用时立即加以利用。有关更多信息,请参阅MongoDB数据库工具文档。

image-20210227112227492
下载后得到压缩包
image-20210227112502136
解压
image-20210227112533887
然后点击进入bin目录,可以看到各种工具,接下来的备份还原就需要用到其中的mongodumpmongorestore
image-20210227112550024
将其中的所有exe文件拷贝到MongoDB安装目录下的bin目录中
image-20210227112729196


备份数据库mongodump

# 导出数据
mongodump -h -port -u -p -d -o# 说明
-h 服务器ip地址(一般不写,默认本机)
-port 端口(一般不写,默认27017)
-u 账号
-p 密码
-d 数据库(不写则表示导出全部)
-o 备份到指定目录下 

1️⃣ 备份所有数据:

MongoDB安装目录下新建一个data_backup目录用于存放所有的备份数据

mongodump -u zsr -p 123456 -o D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data_backup

image-20210227112856405
然后再查看data_backup目录,可以看到备份的所有的数据库
image-20210227113046764

2️⃣ 备份指定数据:

MongoDB安装目录下新建一个data_backup2目录用于存放备份的shop数据库

# 用具有读权限的shop1/shop2用户都可以
mongodump -u shop1 -p 123456 -d shop -o D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data_backup2

image-20210227121409952
然后再查看data_backu2目录,可以看到备份的shop数据库
image-20210227121447341

还原数据库mongorestore

mongostore -h -port -u -p -d --drop 备份数据目录# 说明
-h 服务器ip地址(一般不写,默认本机)
-port 端口(一般不写,默认27017)
-u 账号
-p 密码
-d 数据库(不写则表示还原全部数据)
--drop 先删除数据库再导入,不写则覆盖

1️⃣ 还原所有数据:

首先删除几个数据库
image-20210227121856694
然后输入如下命令从data_backup目录进行恢复

mongorestore -u zsr -p 123456 --drop D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data_backup

image-20210227122122487
然后再次登录查看数据库,可以发现已经恢复
image-20210227123501811

2️⃣ 还原指定数据:

首先删除shop数据库
image-20210227123652763
然后输入如下命令从data_backup2目录恢复shop数据库

# 用具有写权限的shop2用户
mongorestore -u shop2 -p 123456 -d shop --drop D:\JAVA_Environment\MongoDB\mongodb-win32-x86_64-windows-4.4.2\data_backup2\shop

image-20210227124130659
然后再次登录查看shop数据库,可以发现已经恢复
image-20210227124223756



十一、实战可视化管理Robo 3T

常见的可视化管理工具

  • adminMongo:WEB/PC端口网页管理 https://github.com/mrvautin/adminMongo
  • Robo 3T *:客户端软件 https://robomongo.org/download/
  • MongoVUE :客户端软件

1. 下载安装Robo 3T

下载地址:https://robomongo.org/download/

Studio 3TRobo 3T 的区别:前者是商业付费软件,后者开源免费软件

这里选择仅仅下载Robo 3T
image-20210225234019413
填写好信息后点击下载
image-20210225234056240
这里选择下载.exe
image-20210225234215296
下载后得到exe文件
image-20210225235326178
双击运行进行安装,傻瓜式下一部安装完成即可


2. 使用Robo 3T

安装完成后打开
image-20210225235556332
点击Create创建一个链接,添加连接数据库的相关信息
image-20210225235717351
我们开启了身份验证,因此需要填写身份验证的用户名和密码,最后Save
image-20210226000100699
然后点击Connect进行连接
image-20210225235857186
成功连接到数据库
image-20210226000141593
然后就可以可视化进行各种操作



十二、mongoose

1. 简介

mongoose.jsnode中操作mongodb的模块,可以通过node语法实现MongoDB数据库的增删改查

中文网:http://www.mongoosejs.net/

英文网:https://mongoosejs.com/

核心概念

  • schema:约束字段/列数据
  • model:对应集合,用它来实现数据增删改查

2. 安装

Vscode新建并打开一个文件夹,在终端输入如下命令安装mongoose模块

# 安装
npm install mongoose

image-20210227132121270


3. CURD语法

新建一个.js文件,用来连接并操作mongodb数据库

// 一、导入模块
var mongoose = require("mongoose");// 二、连接数据库
const db = mongoose.createConnection('mongodb://user:pass@localhost:port/database',{useNewUrlParser:true,useUnifiedTopology:true},err=>{if(err){console.log('数据库连接失败',err);return;}console.log('数据库连接成功');
})// 三、设置数据类型(声明哪个是集合,限制字段个数和字段类型)
const model = db.model('user',{name:{type:String,default:"username"},age:{type:Number},sex:{type:String}
})// 四、创建实例操作(CRUD)
// -----------------增--------------------
const insertObj = new model(数据对象)
方法一:inserObj.save((err)=>db.close())
方法二:(推荐)
insertObj.save()
.then(res=>{return res
})
.catch(err=>{console.log('插入失败'+err)return false
})// -----------------删--------------------
方法一:model.remove/deleteOne/deleteMany(条件对象,(err)=>db.close())
方法二:(推荐)
model.deleteOne(条件对象)
.then(res=>{return res.deletedCount
})
.catch(err=>{console.log('删除失败'+err)return false
})// -----------------改--------------------
方法一:model.update/updateOne/updateMany(条件对象,数据对象,(err)=>db.close())
方法二:(推荐)
model.updateOne(条件对象,数据对象)
.then(res=>{return res.nModified
})
.catch(err=>{console.log('修改失败'+err)return false
})// -----------------查--------------------
方法一:model.find/findOne(条件对象,要显示的字段数据对象,(err,result)=>db.close())
方法二:(推荐)
model.findOne(条件对象)
.then(res=>{return res
})
.catch(err=>{console.log('查询失败'+err)return false
})

4. 测试

// 一、导入模块
var mongoose = require("mongoose");// 二、连接数据库
const db = mongoose.createConnection('mongodb://shop2:123456@localhost:27017/shop', {useNewUrlParser: true,useUnifiedTopology: true
}, err => {if (err) {console.log('数据库连接失败', err);return;}console.log('数据库连接成功');
})// 三、设置数据类型(声明哪个是集合,限制字段个数和字段类型)
const model = db.model('user', {name: {type: String,default: "username"},age: {type: Number},sex: {type: String}
})// 四、创建实例操作(CRUD)
// -----------------增--------------------
const insertObj = new model({name: "zsr",age: 21,sex: "男"
})
insertObj.save().then(res => {console.log(res)return res}).catch(err => {console.log('插入失败' + err)return false})

然后运行测试:
image-20210228101842532
然后打开Robo 3T查看,可以看到成功插入数据
image-20210228101930327

// -----------------查--------------------
model.findOne({})
.then(res=>{console.log(res)return res
})
.catch(err=>{console.log('查询失败'+err)return false
})//分页
model.find({}).skip(0).limit(1)
.then(res=>{console.log(res)return res
})
.catch(err=>{console.log('查询失败'+err)return false
})

image-20210228103425937



十三、接口

1. 简介

随着移动互联网的发展,客户端层出不穷,微信端、 WEB/PC、APP等等,而后端业务逻辑基本是一致的,如
何做到业务逻辑一次编写,多次/随时接入呢?

image-20210228103629396
就是定义接口,调用接口;

1️⃣ 什么是接口?

就是一个文件,主要响应JSON数据(操作方便,体积小)或XML数据

image-20210228103954884

2️⃣ 接口能干嘛?

  • 数据角度:让项目静态而数据动态
  • 功能角度:短信接口,天气接口,股票接口

3️⃣ 去哪找?

  • 通过node/go/java/php等语言去开发

  • 使用第三方接口

image-20210228104530991

4️⃣ 好处

实现一次编写,多次/随机接入,减小后端工作量,方便维护


2. 接口开发规范(Restful API)

image-20210228105119801

  • 说明RESTful是目前最流行的一种互联网软件架构

  • 作用:声明/提供接口设计原则和约束条件

  • 过程

    后端将资源发布到URL上 => 前端通过URL进行访问 => 并通过HTTP动词表示要对资源进行的操作
    后端定义接口 => 前端请求接口 => HTTP动词表明操作目的(get获取 post新建 put更新)
    
  • 举例

    列表页:访问-/模块名get
    详情页:访问-/模块名/编号get
    添加页:访问-/模块名/createget
    处理:访问-/模块名post
    修改页:访问-/模块名/编号/editget
    处理:访问-/模块名/编号put
    删除:访问-/模块名/编号delete
  • 好处:统一开发规范,便于团队协作

image-20210301110522075


3. 接口测试工具Postman

1. 简介

Postman就是一个用来模拟http请求的工具,用于测试接口,查看接口返回数据

  • 后端调试接口避免出现bug
  • 前端查看接口是否使用并查看返回的数据内容

官网:https://www.postman.com/

2. 下载安装

下载地址:https://www.postman.com/downloads/,选择合适的版本下载
image-20210301110950957
下载后得到.exe文件,双击进行安装即可
image-20210301111110959
安装完成自动打开,出现如下界面,我们可以在官网创建一个账户进行登录,然后即可使用
image-20210301111320063

3. 使用

新建一个request请求
image-20210301111512474
填写相关信息,然后保存
image-20210301111541303
然后填写请求信息,这里以get方式请求https://jsonview.com/example.json
image-20210301111618808

在下面可以看到请求返回的数据



十四、express框架教学系统学生模块接口开发

1. express快速入门

1️⃣ 简介express是基于nodejs开发第一个框架(原理:基于nodejs内置的http模块进行封装),加快项目开发,便于团队协作

官网:https://www.expressjs.com.cn/
image-20210301111923298

2️⃣ 下载

npm install express --save

image-20210301112133869

3️⃣ 简单使用:创建一个js文件

// 1.引入模块
const express = require("express");// 2.创建app对象(底层原理是http模块的createServer)
const app = express()// 3.编写路由
// 语法: app.HTTP请求方式(路径,回调函数)
app.get('/',(req,res)=>{//send是express用来响应数据res.send("hello")
})// 4.启动服务监听端口
app.listen(3000, () => {console.log('http://localhost:3000');
})

运行该js文件测试,打开浏览器3000端口,可以看到效果
image-20210301112704649


2. 教学系统学生模块接口开发

项目总结构:

image-20210301115034468

1. 安装模块依赖

新建一个空目录,用vscode打开,首先安装相关模块

npm install express --save
npm install mogoose
npm install body-parser

2 expree框架搭建,定义路由

新建入口文件student.js,首先快速搭建express框架web服务器,其中定义两个路由:

  • get方式请求/stu,用于添加学生,用stuController.add方法处理(后续编写)
  • post方式请求/stu,用于查询所有学生,用stuController.index方法处理(后续编写)
// 1.引入模块
const express = require("express");
const bodyparser = require('body-parser')
// 2.创建app对象(底层原理是http模块的createServer)
const app = express()
app.use(bodyparser.urlencoded({extended:true}))
app.use(bodyparser.json())
// 3.编写路由
// ----------添加学生-----------
const stuController = require(process.cwd() + '/controller/stuController')
app.post('/stu', stuController.add)
// ----------查询学生-----------
app.get('/stu',stuController.index)// 4.启动服务监听端口
app.listen(3000, () => {console.log('http://localhost:3000');
})

3. mongoose模块操作数据库

在项目目录下新建models包,其中新建stuModels.js,采用mongoose模块实现操作mongodb数据库,定义并暴露两个方法:

  • 添加学生insert
  • 查询所有学生query
// 一、导入模块
var mongoose = require("mongoose");// 二、连接数据库
const db = mongoose.createConnection('mongodb://shop2:123456@localhost:27017/shop', {useNewUrlParser: true,useUnifiedTopology: true
}, err => {if (err) {console.log('数据库连接失败', err);return;}console.log('数据库连接成功');
})// 三、设置数据类型(声明哪个是集合,限制字段个数和字段类型)
const model = db.model('stu', {name: {type: String,default: "zsr"},age: {type: Number},sex: {type: String}
})// insert添加方法
const insert = postData => {const insertObj = new model(postData)return insertObj.save().then(res => {return res}).catch(err => {console.log('插入失败' + err)return false})
}// query查询方法
const query = () => {return model.find().then(res => {return res}).catch(err => {console.log('查询失败' + err)return false})
}// 导出insert方法
module.exports = {insert,query
}

3. 编写路由处理方法

在项目目录下新建controller包,其中新建stuController.js,用于处理路由,其中暴露两个方法:

  • add用于处理post请求/stu添加学生
  • index用于处理get请求/stu查询全部学生
//导入模型
const stuModel = require(process.cwd() + '/models/stuModel')//定义add添加学生方法
const add = async (req, res) => {//1.接收数据let postData = req.bodyconsole.log(postData)//2.过滤(忽略)//3.操作数据库let rs = await stuModel.insert(postData)//4.判断返回if (rs) {res.send({meta: {state: 200,msg: "添加成功"},data: null})} else {res.send({meta: {state: 500,msg: "添加失败"},data: null})}
}//定义index查询学生方法
const index = async (req, res) => {//1.获取数据let data = await stuModel.query()//2.响应数据res.send({meta: {stage: 200,msg: "查询成功"},data: data})
}//导出方法
module.exports = {add,index
}

4. 测试

运行入口文件student.js,然后打开postman进行测试

1️⃣ 首先进行 添加学生 测试,以post方式请求http://localhost:3000/stu
image-20210301114056251
根据返回结果,可以看到成功添加,再回到Robo 3T查看数据库结果,成功添加学生
image-20210301114214452

2️⃣ 然后进行 查询所有学生 测试,以get方式请求http://localhost:3000/stu
image-20210301114311871
根据返回结果,成功查询到学生信息


3. 接口文档开发apiDoc

1. 简介

image-20210301114547742
apiDoc就是nodejs中的一个模块,用于通过注释快速生成接口文档

官网:https://apidocjs.com/

2. 使用

1️⃣ 下载模块,后期通过注释生成接口文档

npm install apidoc -g

2️⃣ 项目根目录下创建apidoc.json文件,格式如下:

{"name": "example","version": "0.1.0","description": "apiDoc basic example","title": "Custom apiDoc browser title","url" : "https://api.github.com/v1"
}

image-20210301115008245

3️⃣ 添加接口注释,在stuController.js处理路由方法中添加注释

//导入模型
const stuModel = require(process.cwd() + '/models/stuModel')//定义add添加学生方法
/*** @api {post} /stu 添加学生* @apiName add* @apiGroup Stu** @apiParam {String} name 学生姓名* @apiParam {Number} age 学生年龄* @apiParam {String} sex 学生性别** @apiSuccess {String} meta 状态码&提示信息* @apiSuccess {String} data 数据*/
const add = async (req, res) => {//1.接收数据let postData = req.bodyconsole.log(postData)//2.过滤(忽略)//3.操作数据库let rs = await stuModel.insert(postData)//4.判断返回if (rs) {res.send({meta: {state: 200,msg: "添加成功"},data: null})} else {res.send({meta: {state: 500,msg: "添加失败"},data: null})}
}//定义index查询学生方法
/*** @api {get} /stu 查询学生列表* @apiName index* @apiGroup Stu** @apiParam {Number} id Users unique ID.** @apiSuccess {String} meta 状态码&提示信息* @apiSuccess {String} data 数据*/
const index = async (req, res) => {//1.获取数据let data = await stuModel.query()//2.响应数据res.send({meta: {stage: 200,msg: "查询成功"},data: data})
}//导出方法
module.exports = {add,index
}

4️⃣ 生成接口文档

apidoc -i ./接口注释目录 -o ./接口文档存放目录

image-20210301115225423

运行以上命令后,项目根目录下生成了doc目录,找到其中的index.html文件
image-20210301115308615
用浏览器打开,就是生成的接口文档
image-20210301115327070


http://www.ppmy.cn/news/605619.html

相关文章

numpy数组方法

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a;https://blog.csdn.net/weixin_37887248/article/details/81744755 </div><!--一个博主专栏付费入口--><!-…

MySQL详细学习教程(建议收藏)

目录1、初识数据库1.1、什么是数据库1.2、数据库分类1.3、相关概念1.4、MySQL及其安装1.5、基本命令2、操作数据库2.1、操作数据库2.2、数据库的列类型2.3、数据库的字段属性2.4、创建数据库表2.5、数据库存储引擎2.6、修改数据库3、MySQL数据管理3.1、外键3.2、DML语言1. 添加…

python图像处理实战(三)—图像几何变换

&#x1f680;写在前面&#x1f680; &#x1f58a;个人主页&#xff1a;https://blog.csdn.net/m0_52051577?typeblog &#x1f381;欢迎各位大佬支持点赞收藏&#xff0c;三连必回&#xff01;&#xff01; &#x1f508;本人新开系列专栏—python图像处理 ❀愿每一个骤雨初…

pytorch.range() 和 pytorch.arange() 的区别

总结&#xff1a; torch.range(start1, end6) 的结果是会包含end的&#xff0c; 而torch.arange(start1, end6)的结果并不包含end。 两者创建的tensor的类型也不一样。 参考&#xff1a; torch.range torch.arange

LeetCode简单题之二进制矩阵中的特殊位置

题目 给你一个大小为 rows x cols 的矩阵 mat&#xff0c;其中 mat[i][j] 是 0 或 1&#xff0c;请返回 矩阵 mat 中特殊位置的数目 。 特殊位置 定义&#xff1a;如果 mat[i][j] 1 并且第 i 行和第 j 列中的所有其他元素均为 0&#xff08;行和列的下标均 从 0 开始 &#x…

数据结构——八大排序算法(面试必备)

目录1. 交换排序——冒泡排序2. 交换排序——快速排序3. 选择排序——简单选择排序4. 选择排序——堆排序什么是堆堆排序基本思想步骤图解代码实现5. 插入排序——简单插入排序6. 插入排序——希尔排序7. 归并排序8. 基数排序1. 交换排序——冒泡排序 从要排序序列的第一个元素…

在CMD命令行中切换到管理员权限模式

1、打开CMD 2、输入&#xff1a; runas /noprofile /user:Administrator cmd 3、输入Administrator账户的密码&#xff0c;必须设置密码 PS&#xff1a;可以不是Administrator账户&#xff0c;只要是具有管理员权限的账号都可&#xff0c;例如ASUS等。 runas /noprofile /us…

LeetCode中等题之根据字符出现频率排序

题目 给定一个字符串&#xff0c;请将字符串里的字符按照出现的频率降序排列。 示例 1: 输入: “tree” 输出: “eert” 解释: e’出现两次&#xff0c;r’和’t’都只出现一次。 因此’e’必须出现在’r’和’t’之前。此外&#xff0c;"eetr"也是一个有效的答案。…