数据库——MongoDB

一、介绍

1. MongoDB 概述

MongoDB 是一款由 C++ 语言编写的开源 NoSQL 数据库,采用分布式文件存储设计。作为介于关系型和非关系型数据库之间的产品,它是 NoSQL 数据库中最接近传统关系数据库的解决方案,同时保留了 NoSQL 的灵活性和扩展性。

核心特性:
  • 文档导向存储:数据以类似 JSON 的 BSON 格式存储

  • 无固定表结构:不需要预先定义严格的表结构

  • 多语言支持:提供 Python、Node.js、Java、C++、PHP、C# 等主流语言的驱动

  • 应用场景广泛:适用于大数据、内容管理、持续交付、移动应用、社交网络、用户数据管理等领域

2. MongoDB 相对于关系型数据库(RDBMS)的优势

优势 说明
灵活的数据模型 无固定结构,数据结构为键值对(key:value)形式,文档类似 JSON 对象
嵌套数据支持 字段值可包含其他文档、数组及文档数组,使数据结构更清晰
无复杂关联 不需要维护表与表之间的内在关联关系,简化数据模型
强大的查询能力 提供类似 SQL 的丰富查询功能,支持基于文档的动态查询
高性能与可扩展 易于调优和扩展,具备高性能、高可用性和可伸缩性特性
对象映射自然 应用程序对象与数据库对象呈现天然对应关系
存储方式灵活 支持基于内存或硬盘文件的存储方式
完善的特性支持 提供丰富的查询操作、索引支持,4.0+版本支持多文档事务

3. SQL 与 MongoDB 核心概念对比

SQL 术语 MongoDB 术语 说明
数据库 (Database) 数据库 (Database) 数据存储的最高层级
表 (Table) 集合 (Collection) 数据记录的容器
行/记录 (Row) 文档 (Document) 单条数据记录,采用 JSON 结构
列/字段 (Column) 字段/键 (Field) 数据记录的属性
主键 (Primary Key) 对象ID (ObjectId) 默认主键格式为 _id: ObjectId("...")
索引 (Index) 索引 (Index) 加速查询的数据结构

4. 适用场景推荐

MongoDB 特别适合以下场景:
  • 需要快速迭代开发的项目

  • 数据结构频繁变化的业务

  • 处理大量非结构化或半结构化数据

  • 需要水平扩展的高流量应用

  • 内容管理系统和博客平台

  • 实时分析和数据处理

传统 SQL 仍更适合:
  • 需要复杂事务处理的应用

  • 数据结构高度规范化的场景

  • 已有成熟的关系型数据模型

提示:MongoDB 4.0+ 已支持多文档 ACID 事务,但在复杂事务场景下仍需谨慎评估性能影响。

二、MongoDB基本操作

1.库管理

显示所有数据库列表:空数据库不会显示,或者说空数据库已经被MongoDB回收了。

bash 复制代码
show dbs
show databases

切换数据库,如果数据库不存在则创建数据库

bash 复制代码
use <database>

查看当前工作的数据库

bash 复制代码
db //是db.getName()的简写

删除当前数据库,如果数据库不存在,也会返回{"ok":1}

bash 复制代码
use <db>    // 先切换到要删除的数据库种,然后才能删除数据库
db.dropDatabase()

查看当前数据库状态

bash 复制代码
db.stats()

在 MongoDB 中,最重要的核心是文档,如果一个库或者一个库下的集合中的文档全部被删除了,则这个库和这个集合就会 MongoDB回收删除。

2.集合管理

创建集合

在 mongodb 中其实不需要专门创建集合,直接添加文档,mongodb 也会自动生成集合

bash 复制代码
// name 为必填参数,options为可选参数。capped若设置值为true,则size必须也一并设置
db.createCollection(
    name=<集合名称>,
    options={
        capped:<boolean>,    // 创建固定集,固定集指限制固定数据大小的集合,当数据达到最大值会自动覆盖最早的文档内容
        size:<bytes_size>,    // 指定固定集合存储的最大字节数,单位:字节数
        max:<collection_size>    // 指定固定集合中包含文档的最大数量,单位:字节数
    });

// 添加文档到不存在的集合中,mongodb会自动创建集合,
// db.<集合名称>.insert(要存储的json数据)

use book_info
db.courses.insert({"name":"python入门","price":31.4})
集合列表
bash 复制代码
show collections    // 或 show tables 或 db.getCollectionNames()
删除集合
bash 复制代码
db.集合名称.drop()
查看集合
bash 复制代码
db.getCollection("集合")
db.集合名称
查看集合创建信息
bash 复制代码
db.printCollectionStats()

三、文档管理

1.数据类型

类型 描述
ObjectID 用于存储文档的ID,相当于主键,区分文档的唯一字段,MongoDB中就是一个对象的返回值
String 字符串是最常用的数据类型,MongoDB中的字符串必须是UTF-8.
Integer 整数类型用于存储数值。整数可以是32位,也可以是64位,这取决于你的服务器。
Double 双精度类型用于存储浮点值,MongoDB中没有float浮点数这个说法
Boolean 布尔类型用于存储布尔值:true/false
Arrays 将数组、列表或多个值存储到一个键
Timestamp 时间戳,用于记录文档何时被修改或创建。Date(),Timestamp(),ISODate()
Object 用于嵌入文档, 相当于子属性是另一个json文档而已,这种方式就可以实现嵌套
Null 空值,相当于pythonNone
Symbol 与字符串用法相同,常用于某些使用特殊符号的语言,二进制
Date 用于以UNIX时间格式存储当前日期或时间。
Binary data 二进制数据,常用于保存文件的内容,往往是图片,数据本身。
Code 用于将 JavaScript代码存储到文档中
Regular expression 正则表达式

2.添加文档

文档的数据结构和JSON基本一样。所有存储在集合中的数据在内部存储的格式都是BSON格式。

BSON是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。

bash 复制代码
//添加文档
//方式1
db.<集合名称>.insert(<document>) // document就是一个json格式的数据

//方式2
db.<集合名称>.insertOne(<document>) // 如果文档存在_id主键为更新数据,否则就添加数据。

//方式3
//一次性添加多个文档,多次给同一个集合
db.<集合名称>.insertMany([<document>,<document>,...])
bash 复制代码
use person

// 添加一条数据
db.user_list.insert({"name":"老李", "age":33, "sex":true, "child":{"name":"小灰灰","age":3}});
// WriteResult({ "nInserted" : 1 })


// 添加一条数据
db.user_list.insertOne({"name":"小张", "age":18, "sex":true});
// {
// 	"acknowledged" : true,
// 	"insertedId" : ObjectId("605021e6d5c7a55cc95c1cb7")
// }


// 添加多条数据
document1 = {"name":"小蓝", "age":16}
document2 = {"name":"小广", "age":16}
db.user_list.insertMany([document1, document2]);

// {
// 	"acknowledged" : true,
// 	"insertedIds" : [
// 		ObjectId("60502235d5c7a55cc95c1cba"),
// 		ObjectId("60502235d5c7a55cc95c1cbb")
// 	]
// }
db.user_list.find()

3.删除文档

bash 复制代码
// 方式1
db.<集合名称>.remove(
   <query>,  // remove的条件,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档
   {
     justOne: <boolean>,      // 可选删除,是否只删除查询到的第一个文档,默认为false,删除所有
     writeConcern: <document> // 可选参数,抛出异常的级别。
   }
)

// 方式2: 删除一条数据
db.<集合名称>.deleteOne(
   <query>,  // removed的条件,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档
   {
     justOne: <boolean>,      // 可选删除,是否只删除查询到的第一个文档,默认为false,删除所有
     writeConcern: <document> // 可选参数,抛出异常的级别。
   }
)
// 方式3:删除多条数据
db.<集合名称>.deleteMany(
   <query>,  // removed的条件,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档
   {
     justOne: <boolean>,      // 可选删除,是否只删除查询到的第一个文档,默认为false,删除所有
     writeConcern: <document> // 可选参数,抛出异常的级别。
   }
)
bash 复制代码
// 添加多条测试数据
document1 = {"name":"小黑", "age":16}
document2 = {"name":"小白", "age":16}
db.user_list.insertMany([document1, document2]);

// 删除满足条件的第一条数据
// 条件 {"age":{$eq:16}}   相当于 age == 16
// db.user_list.remove({"age":{$eq:16}},{"justOne":true})
// 删除满足条件的所有数据,条件中$wq可以不写
// db.user_list.remove({"age":16}); // 等于可以省略不写,相当于 db.user_list.remove({"age":{$eq:16}});

// 删除一条
db.user_list.deleteOne({"age": 16})
// 删除多条
db.user_list.deleteMany({"age": 16})

4.查询文档

bash 复制代码
// 获取一条
db.集合名称.findOne(
	<query>,     // 查询条件,删除、查询、修改都需要条件、条件写法基本一样的。
    {
    	<key>: 0, // 隐藏指定字段,例如:"_id":0,
    	<key>: 1, // 显示指定字段,例如:"title":1,
    	....
    }
)
// 获取多条
db.集合名称.find(
	<query>,      // 查询条件
    {
    	<key>: 0, // 隐藏指定字段,例如:"_id":0,
    	<key>: 1, // 显示指定字段,例如:"title":1,
    	....
    }
)

// 以易读的方式来格式化显示读取到的数据,只能在find方法后面使用。
db.集合名称.find().pretty()
bash 复制代码
// 切换数据库
use person

// 添加测试数据
docs = [
    {"name": "小黄", "sex": 0, "age": 15, "mobile": "13301234568"},
    {"name": "小飞", "sex": 1, "age": 16, "mobile": "1351234568"},
    {"name": "小龙", "sex": 1, "age": 19, "mobile": "15001234568"},
    {"name": "小绵羊", "sex": 0, "age": 13, "mobile": "15001234568"}
]
db.user_list.insertMany(docs);

// 查询一条数据
db.user_list.findOne()  // 获取集合中第一条数据
db.user_list.findOne({})  // 同上
db.user_list.findOne({},{_id:0})  // 获取集合中第一条数据,并隐藏_id
db.user_list.findOne({},{_id:0, name:1, mobile:1})  // 获取集合中第一条数据,只查询文档的name和mobile属性的数据
db.user_list.findOne({name:"小飞"}, {_id:0, name:1, mobile:1})
db.user_list.findOne({name:"小龙", age:19})

// 查询多条数据
db.user_list.find()
db.user_list.find().pretty()
db.user_list.find({sex:1})
db.user_list.find({sex:0}, {_id:0, name:1, mobile:1})

5.比较运算

|-------|---------------------------------------|-------------------------------------|---------------------------|
| 操作 | 格式 | 语法例子 | SQL中的类似语句 |
| 等于 | {<key>:<val>} {<key>:{$eq:<val>}} | db.集合.find({"name":"xiaoming"}) | where name = 'xiaoming' |
| 小于 | {<key>:{$lt:<val>}} | db.集合.find({"age":{$lt:17}}) | where age < 17 |
| 小于或等于 | {<key>:{$lte:<val>}} | db.集合.find({"age":{$lte:17}}) | where age <= 17 |
| 大于 | {<key>:{$gt:<val>}} | db.集合.find({"age":{$gt:17}}) | where age > 17 |
| 大于或等于 | {<key>:{$gte:<val>}} | db.集合.find({"age":{$gte:17}}) | where age >= 17 |
| 不等于 | {<key>:{$ne:<val>}} | db.集合.find({"age":{$ne:17}}) | where age != 17 |
| 包含 | {<key>:{$in:[<val>...]}} | db.集合.find({"age":{$in:[1,2,3]}}) | where age in (1,2,3) |

bash 复制代码
db.user_list.find({"age": {$lte:18}})  // 小于等于
db.user_list.find({"age": {$gte:18}})  // 大于等于
db.user_list.find({"age": {$in:[16,33]}})

// 添加测试数据
db.user_list.insert({"name":"老王", "age":32, "sex":true, "child":{"name":"小王", "age":4}});
db.user_list.insert({"name":"老张", "age":33, "sex":true, "child":{"name":"小张", "age":5}});

db.user_list.find({"child.age": {$gt:3}})
db.user_list.find({"child.age": {$in:[3, 5]}})

6.逻辑运算

|--------------|-----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| $and | {<key>:<val>,<key>:<val>,...} {$and: [{key:{$运算符:<val>}},....]} | db.集合.find({key1:value1, key2:value2}) |
| $or | {$or: [{<key>: {$运算符:<val>}}, ....]} | db.集合.find({$or: [{key1: value1}, {key2:value2}]}) |
| $and$or | {<key>:<val>, $or: [{<key>: {<$运算符>:<val>}},...]} {$and:[{$or:[{<key>:{<$运算符>:<val>}},..]},$or:[{<key>:{<$运算符>:<val>}},..]}]} | db.集合.find({key1:value1, $or: [{key1: value1}, {key2:value2}]}) |
| $not | {<key>:{$not:{<$运算符>:<val>}}} | $not操作符不支持$regex正则表达式操作 |

bash 复制代码
// 查询age=19 并且 sex=1
db.user_list.find({
    $and:[
        {"age":{$eq:19}},
        {"sex":{$eq:1}}
    ]
})
// 简写:
db.user_list.find({
    $and:[
        {"age":19},
        {"sex":1}
    ]
})
// 继续简写;
db.user_list.find({"age":19, "sex":1})


// 查询age=16或者age=18
db.user_list.find({
    $or:[
        {"age":{$eq:16}},
        {"age":{$eq:18}}
    ]
})

// 查询年龄!=16的
db.user_list.find({"age":{$not:{$eq:16}}})
db.user_list.find({"age":{$ne:16}})


// 查询age=33的男生 或者 age=19的男生
db.user_list.find({
    "sex":1,
    $or:[
        {"age":19},
        {"age":33}
    ]
});


db.user_list.find({
    "sex":1,
    "age":{
    	$in:[19,33]
 	}
});


db.user_list.find({
    $or:[
        {$and:[{"sex":1},{"age":19}]},
        {$and:[{"sex":1},{"age":33}]},
    ]
});


db.user_list.find({
    $or:[
        {"sex":1,"age":19},
        {"sex":1,"age":33},
    ]
});

7.排序显示

bash 复制代码
db.集合.find().sort({<key>:1})  // 升序,默认为升序,从小到大
db.集合.find().sort({<key>:-1}) // 倒序


db.user_list.find().sort({age:-1});
db.user_list.find().sort({age:-1, sex:1});

8.字段投影

find()方法默认将返回文档的所有数据,但是可以通过设置find()的第二个参数projection,设置值查询部分数据。

bash 复制代码
// 只显示人名
db.user_list.find({},{'name':1,'_id':0})

9.分页查询

limit方法用于限制返回结果的数量,skip方法用于设置返回结果的开始位置

bash 复制代码
// db.集合.find(...).limit(结果数量).skip(跳过数量)

db.user_list.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5);
db.user_list.find({},{"_id":0,"name":1,"age":1}).sort("age":1}).limit(5).skip(5);

10.更新文档

|----------|----------------------------------------------------------|------------------------------------------------------------------------------|
| 操作 | 语法 | 说明 |
| $inc | db.集合.update({<key1>:<val1>},{$inc:{<key2>:<val2>}}) | 更新key1=val1的文档中key2的值为val2,类似python的递增递减:{ $inc:{<key2>:-<val2>} } |
| $set | db.集合.update({<key1>:<val>}, {$set:{<key2>:<val2>}}) | 更新key1=val1的文档中key2的值为val2,如果key2不存在则新增对应键值对 |
| $unset | db.集合.update({<key1>:<val>}, {$unset:{<key2>:<val2>}}) | 移除key1=val1的文档中key2=val2这个键值对 |
| $push | db.集合.update({<key1>:<val>}, {$push:{<key2>:<val2>}}) | 给key1=val1的文档中key2列表增加1个数组成员val2key2必须是数组。 |
| $pull | db.集合.update({<key1>:<val>}, {$pull:{<key2>:<val2>}}) | 与push相反,给key1=val1的文档中key2列表删除1个指定成员val2 |
| $pop | db.集合.update({<key1>:<val>}, {$pop:{<key2>:<val2>}}) | 给key1=val1的文档中key2列表移除第一个或最后一个成员。val2只能是1(最后面)-1(最前面),与python相反 |

bash 复制代码
// db.user_list.insert({"name":"老李", "age":33, "sex":true, "child":{"name":"小灰灰","age":3}});
// $inc
// 把老李的年龄加10岁
db.user_list.update({"name":"老李"},{$inc:{"age":10}}); // 更新一条
db.user_list.find({"name": "老李"})

// 添加测试数据
documents = [
    {"name":"小明", "age":12},
    {"name":"小明", "age":20},
]
db.user_list.insertMany(documents)

db.user_list.updateMany({"name":"小明"},{$inc:{"age":10}}); // 更新多条

// 把老李的孩子年龄加10岁
db.user_list.update({"name":"老李"},{$inc:{"child.age":10}});


// $set
//更新老李的手机号码
db.user_list.update({"name":"老李"},{$set:{"mobile":"18012312312"}}); // 更新一条
// 更新老李孩子的手机号码
db.user_list.update({"name":"老李"},{$set:{"child.mobile":"18012312312"}});

// $unset
// 移除老李的性别键值对
db.user_list.update({"name":"老李"},{$unset:{"sex":true}});

// $push
db.user_list.update({"name":"老李"},{$set:{"love":["TV","game"]}});
db.user_list.update({"name":"老李"},{$push:{"love":"code"}}); // 往列表属性中追加成员

// $addToSet 结合 $each 批量添加列表中的每一个元素
db.user_list.update({"name":"老李"},{$addToSet:{"love":{$each:["code","music","TV"]}}});

// $pull
db.user_list.update({"name":"老李"},{$pull:{"love":"TV"}});

// $pop
db.user_list.update({"name":"老李"},{$pop:{"love":-1}}); // 左边移除列表的第一个成员
db.user_list.update({"name":"老李"},{$pop:{"love":1}}); // 右边移除列表的最后一个成员

// $rename 字段名重命名
db.user_list.update({"name":"老李"},{$rename:{"love":"lve"}});

四、第三方客户端-pymongo

1.概述

pymongo 是 MongoDB的一个 python 驱动程序,允许你使用 python 来操作 mongodb 数据库。下面将为你介绍pymongo的基本使用,包括安装、连接数据库、创建集合、插入文档、查询文档、更新文档和删除文档。

2.连接数据库

需要安装pymongo:pip install pymongo

bash 复制代码
from pymongo import MongoClient

client = MongoClient('localhost', 27017)  # 连接到本地MongoDB
db = client['py_spider']  # 选择或创建一个数据库

3.文档插入

插入数据时如果集合不存在则新建集合

python 复制代码
from pymongo import MongoClient

mongo_client = MongoClient()
collection = mongo_client['py_spider']['person']

# 插入单个文档
person_info = {"name": "John", "address": "长沙"}
collection.insert_one(person_info)

# 插入多个文档
person_info_list = [
    {"name": "Amy", "address": "上海"},
    {"name": "Hannah", "address": "南京"},
    {"name": "Joe", "address": "上海"}
]
collection.insert_many(person_info_list)

4.文档查询

使用find_one()方法查询单个文档,或者使用find()查询满足条件的多个文档。

python 复制代码
# 查询单个文档
query = {"name": "John"}
document = collection.find_one(query)
print(document)

# 查询多个文档
query = {}
documents = collection.find(query)
for document in documents:
    print(document)

5.更新文档

使用update_one()方法更新单个文档,或者使用update_many()更新多个文档。

python 复制代码
# 更新单个文档
query = {"name": "John"}
new_values = {"$set": {"address": "杭州"}}
collection.update_one(query, new_values)

# 更新多个文档
query = {"address": {"$regex": "上海"}}
new_values = {"$set": {"name": "Minnie"}}
collection.update_many(query, new_values)

6.删除文档

使用delete_one()方法删除单个文档,或者使用delete_many()删除多个文档。

python 复制代码
# 删除单个文档
query = {"address": "杭州"}
collection.delete_one(query)

# 删除多个文档
query = {"address": {"$regex": "^上"}}
collection.delete_many(query)
相关推荐
Estar.Lee3 小时前
MySQL中外键约束详解 外键在表关系维护中的作用
运维·数据库·mysql·api·免费api
灯琰13 小时前
五款MySQL 可视化客户端软件
数据库·mysql
两袖清风9983 小时前
【MySQL】三大范式
数据库·mysql
Wooden-Flute5 小时前
八、数据库恢复技术
服务器·数据库·oracle
南棱笑笑生5 小时前
20250611在全志H3平台的Nano Pi NEO CORE开发板上运行Ubuntu Core16.04时让4G模块EC200A-CN使用AT命令拨号上网
linux·数据库·ubuntu
文牧之6 小时前
PostgreSQL 的扩展pg_surgery
运维·数据库·postgresql
眠修6 小时前
MongoDB 数据库应用
数据库·mongodb
wh_xia_jun7 小时前
mybatis xml 配置中,jdbcType=VARCHAR 的作用
数据库·oracle·tomcat
程序猿小D8 小时前
第24节 Node.js 连接 MongoDB
数据库·mongodb·npm·node.js·编辑器·vim·express