自学数据库- MongoDB

NoSQL

NoSQL 指的是非关系数据库。NoSQL 使用的最多的就是 key-value 存储,当然还有 xml 等类型。NoSQL 对于传统关系数据库的优点有:

  • 能够提供对数据库高并发的读写
  • 能够满足对海量数据的高效率存储和访问的需求
  • 有较高的可扩展性和可用性

MongoDB 介绍

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 json 的 bjson 格式,因此可以存储比较复杂的数据类型。MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。

  • 面向集合 (Collenction-Orented)
    意思是数据被分组存储在数据集中,被成为一个集合 (Collenction)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库里的表 (table),不同的是它不需要定义任何模式 (schema)
  • 模式自由 (schema-free)
    意味着对于存储在 MongoDB 数据库中的文件,我们不需要知道它的任何结构定义。例如,下面两个记录可以存在于同一个集合里面:{'welcome" : “Beijing”} {“age” : 25 }
  • 文档型
    意思是我们存储的数据是键-值对的集合。键是字符串,值可以是数据类型集合里的任意类型,包括数组和文档。这个数据格式称作 “BSON” (Binary Serialized document Notation)

MongoDB 的下载和安装

据说 7.0 和之前版本不兼容了,也有很多变化,本文是基于5.0的版本,应该和6.0兼容。

MongoDB 官网
MongoDB 官方中文文档
MongoDB 中文网
MongoDB 社区版下载

基于 linux

mongodb 无法使用包管理器安装,所以需要从官网找到连接然后使用 wget 下载安装。需要注意的是,官网默认提供的是 .deb 文件,是 Debian 的安装包,所以最好选择下载 tgz 压缩包。

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2204-7.0.6.tgz

下载完成后,解压缩压缩包

tar -zxvf mongodb-linux-x86_64-ubuntu2204-7.0.6.tgz

然后将解压出来的目录移动到指定目录中,也可以重命名

mv mongodb-linux-x86_64-ubuntu2204-7.0.6.tgz/ ~/mongodb

进入该目录,创建存储数据库和log文件的目录,并设置权限

cd ~/mongodb
mkdir -p data/db
mkdir -p data/log
chown `id -u`:`id -g` data/db
chown `id -u`:`id -g` data/log

配置启动文件

创建配置文件

mkdir conf
vim conf/mongod.conf

在配置文件中输入

storage:
   dbPath:~/mongodb/db
 systemLog:
   destination: file
   logAppend: true
   path: ~/mongodb/log/mongod.log
 net:
   bindIp: 0.0.0.0
   port: 27017
 security:
   authorization: disabled

使用此配置文件运行 mongo 服务,则可以远程不经过验证访问了。

配置访问权限

使用客户端登录数据库,然后可以创建管理员用户,然后可以创建普通用户并赋予管理员权限

use admin
db.createUser({
  user: "root",
  pwd: "root",
  roles: [{ role: "root", db: "admin" }]
})

然后可以将配置文件中 authorization 项的 disabled 改为 enabled,再重启服务,就可以使用访问权限登录了

设置为系统服务,自动执行

首先需要自定义服务文件 /etc/systemd/system/mongodb.service

[Unit]
Description=MongoDB Database Service
After=network.target

[Service]
User=root
Group=root
ExecStart=~/mongodb/bin/mongod --config ~/mongodb/conf/mongod.conf
ExecStop=/bin/kill -s SIGTERM $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

然后重新加载 systemd 的配置,并启动mongodb服务

systemctl daemon-reload
systemctl enable mongodb.service
systemctl start mongodb.service

基于 windows

MongoDB 是绿色的,官网提供的安装包其实是将一些配置信息在安装阶段运行了。如果使用压缩文件,解压后需要进行配置。

设置文件

可以创建一个文本文件,名称任意取。文件中的参数以 " 键 = 值 " 的格式进行存储,例如

#数据库数据存放目录
dbpath="D:\MongoDB\db"
#数据库日志存放目录
logpath="D:\MongoDB\logs\mongodb.log"

主运行文件和简单的运行参数

文件夹 bin 下的 mongod.exe 为主运行文件,在命令行里输入 mongod.exe -hmongod.exe --help 则能看到参数及说明。

运行 MongoDB 时,必须添加的参数就是数据库路径了。通常还会添加一个日志文件路径:

mongod.exe --dbpath ./db --logpath ./logs/mogondb.log

执行完成后可以开个浏览器进行测试:在浏览器中输入http://localhost:27017/可看到返回信息:

It looks like you are trying to access MongoDB over HTTP on the native driver port.

如果看到这个信息说明程序正常运行。如果需要其他配置可以参考参数说明。

以本地服务方式运行

在命令行界面输入以下命令即可安装为服务,记得添加包括数据库路径在内的其他参数。

mongod.exe --serviceName MongoDB --install

安装完成后,可以在服务中看到,也可以手动运行服务 net start MongoDB 或手动停止服务 net stop MongoDB

如果不需要服务了,则可以进行卸载

mongod.exe --remove

MongoDB 的使用

MongoDB 与 Sql 的概念对比

SQLsql说明MongoDBmongodb说明
database数据库database数据库
table数据表collection数据集合
rowdocument or BSON document文档
colunmfield字段
index索引index索引
primary key主键_id(auto set)id(自动设置)

MongoDB 数据类型

类型名称
Object ID对象ID
String字符串,最常用,必须是有效的UTF-8
Boolean布尔
Integer整数
Double浮点
Arrays数组或列表,多个值存储到一个键
Object用于嵌入式的文档对象,即一个值为一个对象
Null存储Null值
Timestamp时间戳
Date当前日期或时间的UNIX时间格式

第一次连接到 MongoDB

在连接之前先要运行 MongoDB,无论是本地服务运行还是命令行运行都行。第一次运行不要加 --auth 即不要进行登录验证。

运行完 MongoDB 就可以连接到 MongoDB 了。使用 bin 目录下的 mongo.exe (据说新版本的 MongoDB 客户端改成了 mongosh.exe)进行连接,如果没有过多的设置直接运行就行了,如果有设置 IP 和端口号,则需要以参数形式传入,例如 mongo 127.0.0.1:27017

设置超级管理员账号

第一次连接上数据库,需要做的就是建立超级管理员账号。

use admin		// 使用 admin 数据库

db.createUser({
  user: 'admin',    // 用户名(自定义)
  pwd: 'Abc123++',  // 密码(自定义)
  roles:[{
    role: 'root',   // 使用超级用户角色
    db: 'admin'     // 指定数据库
  }]
})

设置完成,可以通过指令 show users 查看是否设置成功。然后关闭 MongoDB 服务程序,以需要验证模式重新部署服务即可使用权限设置了。

如果忘记了超级管理员账号密码,可以以不需要认证的形式部署服务。这时连接到数据库不需要账号密码,使用客户端连接到数据库。

use admin		// 使用 admin 数据库
db.system.users.find() 	// 查看当前用户
db.system.users.remove({})		// 删除现有的用户

db.createUser({user:"admin",pwd:"Admin@123",roles:["root"]})		// 创建超级管理员账号

然后再开启验证重新部署服务就可以了。

shell 下使用账号登录

使用客户端连接到数据库后

use admin
db.auth('admin','Admin@123')

MongoDB 的操作

数据库实例的操作

  1. 查看数据库
    列出所有物理上存在的数据库

show dbs

  1. 切换/创建数据库
    如果数据库不存在,则指向数据库,但不创建。直到插入数据或创建集合时数据库才被创建

use 数据库名

  1. 删除数据库
    删除当前指向的数据库,如果数据库不存在,则什么也不做

use 数据库名
db.dropDatabase()

集合的操作

集合相当于 sql 里的表

  1. 创建集合 (实际操作中,可以绕过此步骤,直接在集合中存储数据,这样会自动创建相应集合)

db.createCollection(集合名)
db.createCollection(集合名,{capped:true,size:num})

参数 capped 默认是 false,表示不设置上限,如果使用 true,则要在 size 中输入该集合的最大数据数量限制

  1. 查看集合

show tables
show collections

  1. 删除集合

db.集合名称.drop()

数据的操作

首先需要明确的是 MongoDB 中数据是以 文档(document) 形式存在,相当于 sql 里的 row。通常 document 是以字典形式存在。在 MongDB 中,唯一的主键是 _id,它是数据创建时自动生成的(除非主动创建)。另外 MongoDB 是 没有表结构 一说的,上一条数据和下一条数据可以完全没有相同的字段,两个数据可以没有任何关联(除了都有_id)。

  1. 新增数据: 新增数据可以使用 insertsave 两种方式,数据以字典或字典列表形式存在。
    insertsave 都可以新增数据,区别在于 insert 不会遍历检测数据,而是直接插入,如果有重复数据则报错。save 会遍历检测数据,有重复数据则更新。

db.集合名称.insert(document)
db.集合名称.save(document)
增加多条数据使用字典列表:
db.集合名称.insert([{k1:v1},{k2,v2}]

insert 方法将在未来弃用,改为使用 insertOne() 方法,使用方式是一样的。相对于 insertOne(),还有 insertMany() 方法。相同 save() 方法在将来也会被弃用。

  1. 修改数据:修改数据使用 update 命令,其有3个参数:query 是查询条件,类似 where;update 是更新的数据,类似 set;multi 可选,默认false ,是否更新全部满足条件的文档(false则只更新第一条)
    需注意的是 MongoDB 是全文档更新的,如果参数 update 部分没有的字段,即使原数据有也会丢失。所以通常会将 update 部分增加 $set ,表示只修改更新部分,不修改文档结构。

db.集合名称.update({query},{update},{multi:false})

# 只更新找到的第一条数据,且会修改结构,结果
db.person.update({name:"zs"},{age:16})
# 只更新第一条数据,不修改文档结构
db.person.update({name:"zs"},{$set:{age:123}})
# 更新所有所有符合查询条件的数据
db.person.update({name:"zs"},{$set:{age:40}},{multi:true})

update() 方法在未来将被弃用,改为使用 updateOne() 方法

  1. 删除数据:删除数据使用 remove 命令,其参数为查询条件,如果没有参数则是不进行查询删除全部。

db.集合名称.remove(查询条件)

# 删除所有匹配数据
db.person.remove({name:"zs"})
# 只删除第一条匹配数据
db.person.remove({name:"zs"},{justOne:true})
# 不计条件删除全部
db.person.remove({})

remove() 方法在未来将被弃用,可以使用 deleteOne()deleteMany()findOneAndDelete() 方法替代

  1. 查找数据:查找数据使用 findfindOne 命令,区别在于查询全部还是查询第一条符合条件的数据。参数为查询条件,如果没有参数则是查询全部数据。

db.集合名称.find(查询条件)

# 查询所有 name 为 zs 的数据
db.person.find({name:"zs"})
# 查询所有数据
db.person.find()

另外在查询时使用 pretty() 方法,可以格式化输出,方便查看

db.集合名称.find().pretty()

查询

简单查询

Mongo 支持的运算符有:

语法操作格式
$eq等于{key:value}
$lt小于{key:{$lt:value}}
$lte小于等于{key:{$lte:value}}
$gt大于{key:{$gt:value}}
$gte大于等于{key:{$gte:value}}
$ne不等于{key:{$ne:value}}
$or{$or:[{条件1},{条件2}]}
$and{$and:[{条件1},{条件2}]} 或 {{条件1},{条件2}}
$not{$not:{条件}}
$nor或非(非取反){$nor:[{条件1},{条件2}]}
$exists键是否存在{key:{$exists:true|false}}
$in在列表中{key:{$in:[value1,value2]}}
$nin不在列表中{key:{$nin:[value1,value2]}}
$mod数字模操作{key:{$mod:[num1,num2]}}
# 查询所有 age 的值 大于16 的数据
db.person.find({age:{$gt:16}})
# 查询所有 age 大于等于18 或 name 等于 'zs' 的数据
db.person.find({$or:[{age:{$gte:18}},{name:"zs"}]})

另外还可以根据某一个字段(key)的值的数据类型进行查询,使用 $type,格式为 {key:{$type:数据类型值}}。数据类型和其值可以参考下表

类型数字备注
Double1
String2
Object3
Array4
Binary data5
Undefined6已废弃
Object id7
Boolean8
Date9
Null10
Regular Expression11
JavaScript13
Symbol14
JavaScript (with scope)15
32-bit integer16
Timestamp17
64-bit integer18
Min key255Query with -1.
Max key127
# 这两种方式等价
db.person.find({name:{$type:2}})
db.person.find({mame:{$type:'string'}})

模糊查询

mongo 没有 like ,而是使用正则表达式。使用 // 或 $regex 可以编写正则表达式

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

自定义查询

可以使用 $where 后面跟一个函数(JS的语法),则可以返回满足条件的数据

db.person.find({$where:function(){return this.age>20}})

查询结果分页

可以使用 limit 将查询结果分页处理,用于读取指定数量的文档

db.集合名称.find(查询条件).limit(NUMBER)

跳过

使用 skip 跳过指定数量的文档,即前指定数量的文档在查询结果中不返回

db.集合名称.find(查询条件).skip(NUMBER)

排序

使用 sort 可以对查询结果集按照字段进行排序,参数1为升序 0 或 -1 为降序

db.集合名称.find().sort({key1:1|0,key2:1|0…})

统计

使用 count 可以对查询结果集中的文档数据量进行统计

db.集合名称.find(查询条件).count()

投影

使用 find() 方法查询到的数据是全部的字段,如果只需要其中部分字段,可以添加参数

db.集合名称.find(查询条件, 投影条件)
例如 db.test.find({age:{$gt:18}}, {name: 1}) 就是只显示 name 字段,1 表示显示,0为不显示,_id 默认是显示的

去重

使用 distinct() 方法可以去重查询,代替了 find() 方法。需注意的是,去重是根据筛选字段进行去重的

db.集合名称.distinct(字段名, 查询条件)

多级查询

当某一条数据某一的字段的值是字典时,可以进行使用点进行多级查询例如

# 文档为: {'name': {'first': 'Joe', 'last': 'Schome'}, 'age': 45}
# 查询姓名为 Joe Schmoe 的记录,以下2个方法是等价的
db.person.find({'name.first': 'Joe', 'name.last': 'Schome'})
db.person.find({'name':{'first': 'Joe', 'last': 'Schome'}})

聚合操作

使用 aggregate() 方法可以进行聚合操作

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

常用的聚合管道有:

$group: 
  将集合中的⽂档分组, 可⽤于统计结果
  
$match: 
  过滤数据, 只输出符合条件的⽂档
  
$project: 
  修改输⼊⽂档的结构, 如重命名、增加、删除字段、创建计算结果
  
$sort: 
  将输⼊⽂档排序后输出
  
$limit: 
  限制聚合管道返回的⽂档数
  
$skip: 
  跳过指定数量的⽂档, 并返回余下的⽂档
  
$unwind: 
  将数组类型的字段进⾏拆分

常用表达式有:

$sum: 
  计算总和, $sum:1 表示以⼀倍计数
  
$avg: 
  计算平均值
  
$min: 
  获取最⼩值
  
$max: 
  获取最⼤值
  
$push: 
  在结果⽂档中插⼊值到⼀个数组中
  
$first: 
  根据资源⽂档的排序获取第⼀个⽂档数据
  
$last: 
  根据资源⽂档的排序获取最后⼀个⽂档数据
$group

$group用于分组,_id 是分组依据,和数据里的_id 是不一样的,使用某个字段的格式为 “$字段”。需要注意的是分组中返回的字段均是分组管道中定义的,除了 _id 是分组条件,其他的可以自定义,可以是中文。

db.stu_info.aggregate(
  {$group: {_id: "$gender", counter: {$sum: 1}}}
)

按照字段 gender 分组,并且统计数据

db.stu_info.aggregate(
  {$group: {_id: "$gender", counter: {$sum: 1}, avg_age: {$avg: "$age"}}}
)

除了统计数据外,还根据 ‘age’ 字段取平均值

db.stu_info.aggregate(
  {$group: {_id: null, counter: {$sum: 1}, avg_age: {$avg: "$age"}}}
)

_id: null 表示没有分组依据字段,即所有文档分为一组

$project

$project 用于修改文档的结构,例如:重命名、增加字段、删除字段、创建计算结果等

db.stu_info.aggregate(
  {$project: {_id: 0, name: 1, age: 1}}
)

类似于投影,不显示 _id,显示 name,显示 age

多个聚合可以一起使用

db.stu_info.aggregate(
  {$group: {_id: "$gender", count: {$sum: 1}, avg_age: {$avg: "$age"}}},
  {$project: {"性别": "$_id", "人数统计": "$count", "平均年龄": "$avg_age", _id: 0}}
)

gender 分组查询后,将各字段名称按需求更改一下

$match

$match 用于过滤数据,只输出符合条件的文档,另外 match 是管道命令,能将结果交给下一个管道,find() 无法实现

db.stu_info.aggregate(
  {$match: {age: {$gt: 20}}}
)

查询 age 字段大于 20 的文档,类似于 find() 方法的结果

db.stu_info.aggregate(
  {$match: {$or:[{age: {$gt: 20}},{hometown: {$in: ["蒙古", "大理"]}}]}},
  {$group: {_id: "$gender", counter: {$sum: 1}}},
  {$project: {"性别": "$_id", "统计人数": "$counter", _id: 0}}
)

过滤后分组再重命名字段

$sort

$sort 可以将输入文档排序后输出

db.stu_info.aggregate(
  {$sort: {age: 1}}
)

按 age 字段升序

db.stu_info.aggregate(
  {$group: {_id: "$gender", counter: {$sum: 1}}},
  {$sort: {counter: -1}}
)

按照 counter 降序排列

$limit 与 $skip

$limit 可以限制聚合返回的文档数,$skip 可以跳过指定数量的文档,两者结合起来就是分页查询

db.stu_info.aggregate({$skip: 5}, {$limit: 5})

返回从第6条开始的5条数据,即每页5条,取第2页

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值