MongoDB 入门操作(Introduction to MongoDB Operations)

MongoDB 入门操作
目录
MongoDB 属于非关系型文档数据库
系统的典型代表非常适合处理大规模数据流、高强度并发访问以及非规律分布的数据特征,并且在爬虫技术中得到了广泛应用
开发的存储后端。
当应用场景对表内查询要求不高且反而是需要大量存储关联性较弱的数据时,在这种情况下,则适合使用 MongoDB 的文档型数据库。
在 MongoDB 系统中,默认采用"系统库、集合体、数据块、属性"的方式进行数据存储,在初看似乎与传统关系型数据库存在明显的不同
的“库、表、行、列”的结构非常相似。
但 MongoDB 无需预先设定数据表架构,在复杂环境下能够灵活支持随时增删改查的数据字段。此外,其并发处理速度显著优于传统的关系型数据库。
本文内容将向大家介绍 MongoDB 中的基本增删查改操作,并通过实例演示帮助大家快速掌握或深入理解 MongoDB 数据库的操作方法~
简介
MongoDB是一种基于分布式文件存储的开源数据库语言;它由C++编程语言开发;致力于通过提供高效的扩展性数据存储解决方案来支持Web应用程序;属于非关系型数据库体系中的一种;在某种程度上类似于传统的关系型数据库体系;其支持的数据结构非常多样化且灵活;能够存储复杂的数据类型如文档、数组和嵌套文档等
主要特点
- 高性能特性:MongoDB展现出卓越的读写性能,在实时数据处理方面表现尤为出色。
- 简便的部署与使用流程:其安装与操作相对直观简便,特别适合快速搭建及开发环境。
- 支持无模式架构以适应快速变化的应用需求:MongoDB采用无模式设计理念,在面对快速变化的应用场景时展现出极佳灵活性。
- 卓越的可扩展能力:通过高效的分片机制实现水平扩展策略,在处理大规模数据及高并发访问任务时展现出显著优势。
- 强大的查询功能支持:不仅提供类似于关系型数据库的标准查询语法(SQL),还支持复杂的条件查询、排序操作及聚合运算等功能。
- 高度可靠的可用性保障:借助复制集技术和分区策略实现数据冗余存储与故障自动切换机制,在确保数据持续可用方面表现出色。
应用场景
- 网络环境中的数据 :MongoDB特别适合支持实时的数据增删查改,并能够满足现代网络环境下的高效率需求。
- 高扩展性的应用场景 :此类场景通常由几十到几百台服务器构成的分布式系统来实现。
- 低效价值的数据 :对于那些在传统数据库中存储成本较高的高效价值型数据而言,MongoDB提供了一种更为经济的选择方案。
- 高效缓存层应用 :基于其高效的性能特性,MongoDB非常适合作为信息基础设施中的缓存层应用。
- 一. 数据库与集合操作
- 如果你使用 Navicat 连接 MongoDB 数据库系统, 你可以通过右键菜单选择创建新的MongoDB实例和集合选项来实现功能。
**

**
保存
详细描述了如何通过Navicat软件创建MongoDB数据库及其集合。需要注意的是,在创建集合的过程中,只有当您点击左上方的【保存
接下来,我们通过 MongoDB 自带的mongosh 命令行终端创建数据库与集合。
**

**
运行 mongosh admin 能够方便地打开一个 Mongo Shell 并将默认数据库设置为 admin;如果希望更改默认数据库,则应选择命令 use admin 进行切换。
建议首先通过调用db.auth方法来实现登录认证,并且必须保证登录用户的相应操作权限。
最后一步,请运行命令 \texttt{show dbs} 以查看我们刚刚通过 Navicat 创建的数据库 \texttt{db1} 的详细信息。 接下来,请切换到数据库 \texttt{db1} ,进入集合列表页面进行查看。您将能够在这里找到通过 Navicat 创建的集合 \texttt{example\_1} ,以便进一步操作。

下面,我们使用db.dropDatabase() 删除当前数据库 db1。

我们注意到尽管命令行提示符
仍然是db1 ,但事实上原数据库已不存在。为了避免混淆,请注意接下来我们将新建一个命名为 db_1 的新数据库。

我们发现,在\texttt{db}.\texttt{create}命令中,并没有被称作"创建数据库"的功能。实际上这一点很容易理解,“\texttt{db}"代表的是现有的数据(\texttt{data}),在现有数据库的情况下"创建新的数据库"在逻辑上是不一致的。
在 MongoDB 中, 创建数据库本质上就是调用一个不存在的新库, 但是在此期间, 数据库仍然未被真正地生成. 唯一的变化仅仅是终端窗口切换成了 my_db> 这一名称.
接下来,在调用db.createCollection执行操作时会生成新的集合结构;当完成此操作后才能查看到被创建的数据库 my_db ,可以通过运行 show collections 命令来获取相关信息以了解已建立的集合情况

此外,在调用db.createCollection时还可以传递一个参数

在初始化example_data_2集合时设置了capped字段为true值,这表示该集合将启用一个数据上限限制机制,在集合文档数量达到预先指定的上限(此处由参数size确定)之前不会进行数据覆盖操作;具体而言,在集合文档数量达到该上限后将覆盖之前的存入数据,默认情况下该上限值被设定为1 GB

最后,使用db.集合名称.drop() 命令即可删除某个集合。

下面的表格总结了本部分用到的命令行和函数。
| 命令行 | 作用 |
|---|---|
| db.auth('username', 'passwd') | 用户登录认证。 |
| show dbs | 返回数据库列表。 |
调用
二. 文档操作
关于文档信息的增删改查操作是所有数据库的核心功能。接下来我们将深入探讨如何向集合中添加数据,并完成查询、修改和删除操作等关键步骤。
2.1 插入文档
MongoDB 的集合无需像传统关系型数据库那样预先设定表结构,并非需要预先定义表结构;我们可以直接向指定集合中添加JSON字符串以完成操作。
db.example_data_1.insertOne({
"name": "Alex",
"age": 20,
"city": "BeiJing"
})
运行结果:

当将包含JSON字符串描述的数据加入集合时, 系统就会自动生成一个带有\_id字段的记录, 并将其称为Object ID. 该字段用于唯一标识每个文档.
Object ID 为一个 12 字节的十六进制数,由四部分组成:
时钟字段(占据前4个字节)
机器码字段(占据接下来3个字节)
进程ID字段(占据接下来2个字节)
自增计数器
- (最后 3 个字节)
比如,666279339a65012180002365 前八个字符为 66627933 ,我们利用 Python 转换为十进制数还原为日期时间。
>> a = 0x66627933
3. >> a
1717729587
>> from datetime import datetime
8. >> datetime.fromtimestamp(1717729587)
datetime.datetime(2024, 6, 7, 11, 6, 27)
随后继续将一条新的文档插入到集合 example_data_1 中;相较于之前的做法,在数据结构上有所改进:新增了一个字段 job,并缺失了 city 字段。
db.example_data_1.insertOne({
"name": "Bob",
"age": 30,
"job": "programmer"
})
运行结果:

新的数据同样以顺利的方式插入到了集合中;查询缺失的字段时会返回Null值。 接下来我们将继续向数据库中插入一条完整的记录,在这条记录中包含了所有的字段信息;然而需要注意的是,在年龄属性上与之前的记录有所区别。
db.example_data_1.insertOne({
"name": "Chandler",
"age": '28',
"city": "Shanghai",
"job": "lawyer"
})
运行结果:

利用『类型颜色』标记不同类型的值后进行观察发现:尽管最后一条文档的字段名age为字符串类型而前两条均为数字字段时仍可成功插入。
虽然 MongoDB 支持同一个字段存储不同类型的数据显示,在设计数据库时最好确保每个字段只有一种数据类型以避免混淆并提高查询效率
与insertOne 相对的是 insertMany ,允许我们依次插入多条记录:
db.example_data_1.insertMany([
{
"name": "David",
"age": 40,
"city": "Chongqing",
"job": "farmer"
},
{
"name": "Ganler",
"age": 33,
"city": "Nanjing",
"job": "worker"
},
{
"name": "Monica",
"age": 27,
"city": "Hangzhou",
"job": "teacher"
},
])
运行结果:

2.2 查询文档
查询所有数据:
db.集合名称.find()
示例:查询example_data_1 集合的所有数据。

查询指定记录:
db.集合名称.find(条件文档)
、比如,下面的语句返回集合中年龄等于33 并且城市为 Nanjing 的记录。
db.example_data_1.find({
'age': 33,
'city': 'Nanjing'
})
✍ 查询文档包含多个字段时,表示这些字段需要同时满足。
查询结果:

如果我们使用的筛选条件不是基于等于号而是某个区间,则要如何撰写相应的筛选规则?例如,在数据库查询中使用圆括号()包围闭合区间表示法来指定年龄在20到30岁之间(不包含30岁)的记录。
此时,在遇到这种情况时(即当需要处理某个特定场景时),我们需要将原有数值部分重新组织成为一个字典结构。该字典中的键字段对应不同范围的操作符类型(即每个操作符代表不同的数据区间),而其对应的值字段则存储各个区间的具体边界数值。
db.集合名称.find({字段1: {操作符1: 边界1, 操作符2: 边界2, ...}, 字段2: ...})
其中 MongoDB 提供的范围操作符总结如下:
| 操作符 | 含义 |
|---|---|
| $gt | > |
| $gte | > = |
| $lt | < |
| $lte | < = |
| $ne | != |
下面的语句查询年龄在[20,30) ,并且城市不在北京的记录:
db.example_data_1.find({
'age': {
'$gte': 20,
'$lt': 30
},
'city': {
'$ne': 'BeiJing'
}
})
查询结果:

集合的find 命令其实可以接收两个参数:
db.集合名称.find(用于过滤记录的文档, 用于限定返回字段的文档)
在字段限定文档中,使用的键为字段名,对应的值只有0 和 1 两种情况:
- 如果值为 0 ,表示在全部字段中剔除值为 0 的字段,并返回剩余字段。
- 如果值为 1,表示仅返回值为 1 的字段。
✍ 注意不能混合使用
0和1,会导致 MongoDB 报错。
下面,我们来查询example_data_1 中的所有记录,但仅返回 name 和 age 字段。
db.example_data_1.find({}, {
'name': 1,
'age': 1
})
查询结果:

在查询结果中不仅包含name 和 age字段还会包含Object ID字段这是因为其原因在于Object ID字段不受上述筛选条件的影响默认情况下会在所有返回的结果中出现
如不需要返回_id 字段,MongoDB 允许我们在字段限定文档中明确 _id 为 0 。

最后,我们来看几个经常用在find 调用结果上的方法。
count 命令
当我们希望统计符合特定条件的记录数量时,在数据库查询中当我们使用find命令后立即调用count命令能够有效地获取所需的结果数量。

limit 命令
当需要设置对find命令返回结果的数量限制时,在find命令的结果基础上配合使用limit指令设定最大返回数量,并使实际返回的数量根据具体情况自动调整。

**sort 命令 **
按照查询结果进行排序,并采用sort命令;该命令根据文档指定排序依据使用的字段,并根据是升序还是降序来确定排序方式。

其中,字段值为 1 表示升序,字段值为 -1 则表示降序。
该命令按age字段进行升序排序;然而最后一条记录中的数值 28 实际上是以字符串形式存储为 '28' ,因此与我们预设的排序结果不符。这也反映出为何我们需要确保 MongoDB 数据库中同一集合内各字段保持统一的数据类型而采取的一种必要措施;如果不这样做可能会遇到不可预见的问题。
2.3 修改文档
文档中的更新操作包括updateOne 和 updateMany ,它们的参数完全相同 ,主要区别在于:
- **
updateOne仅处理第一条符合条件的数据 - **
updateMany处理全部符合规定的信息
我们以updateOne 为例,更新操作的语法如下:
db.集合名称.updateOne(
用于过滤记录的文档,
{"$set": {'字段1':'值1', '字段2': '值2', ...}}
)
下面,我们将chandler 的年龄由字符串 28 改为数字 28 :
db.example_data_1.updateOne(
{'name': 'Chandler'},
{'$set': {'age': 28}}
)

下面让我们来看一下这个示例:我们将集合中没有指定的 city 和 job 字段的记录进行处理,并且将 city 全部更改为 Beijing ,同时将 job 全部更改为 programmer 。

在本节中,我们建议将find替换为更高效的函数名称updateMany。在此基础上添加更新逻辑:json{'$set': {'city': 'Beijing', 'job': 'programmer'}}```
db.example_data_1.updateMany(
{'$or': [{'city': {'$exists': false}}, {'job': {'$exists': false}}]},
{'$set': {'city': 'Beijing', 'job': 'programmer'}}
)
运行结果:相关的两条记录字段值都得到了更新。

2.4 删除文档
文档的删除命令也被划分为deleteOne和deleteMany两种类型。其中前一种命令仅负责处理第一条符合条件的信息,而后一种则会清除所有符合指定条件的信息。
为了避免误删数据,默认的做法是在确认过滤条件无误的情况下,在数据库中进行查询操作以获取相关信息,并随后移除这些记录。例如,在确认过滤条件无误的情况下,在数据库中进行查询操作以获取相关信息,并随后移除这些记录。

[acknowledged](https://zhida.zhihu.com/search?content_id=244091846&content_type=Article&match_order=1&q=acknowledged&zhida_source=entity "acknowledged")
为true 表示数据删除成功,deletedCount 表示一共删除了 2 条数据。
三. 数据去重
去重操作涉及的命令为\texttt{distinct} ,其具体形式如下,在这种情况下第二个参数可选。
db.集合名称.distinct('字段名', 用于过滤记录的文档)
我们可以通过运行 insertMany 语句来生成一组包含年龄、城市和职业重复项的数据集,并将其用于演示消除重复查询结果的过程。
db.example_data_1.insertMany([
{
"name": "Albert",
"age": 40,
"city": "Chongqing",
"job": "farmer"
},
{
"name": "Doris",
"age": 33,
"city": "Nanjing",
"job": "worker"
},
{
"name": "Tom",
"age": 27,
"city": "Hangzhou",
"job": "teacher"
},
])
未去重的查询结果
:

查询city 字段去重后的结果:
**

**
distinct 是一种集合类别的函数,在实际操作中可以直接作用于集合对象获取所需数据。其返回结果是一个数组,并且包含的是经过去重后的数据值。接下来我们将指定第二个参数,在特定条件下对 job 字段的数据进行去重处理

以上就是本篇文章的全部内容啦~
