数据库——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回收了。
show dbs
show databases
切换数据库,如果数据库不存在则创建数据库
use <database>
查看当前工作的数据库
db //是db.getName()的简写
删除当前数据库,如果数据库不存在,也会返回{"ok":1}
use <db> // 先切换到要删除的数据库种,然后才能删除数据库
db.dropDatabase()
查看当前数据库状态
db.stats()
在 MongoDB 中,最重要的核心是文档,如果一个库或者一个库下的集合中的文档全部被删除了,则这个库和这个集合就会 MongoDB回收删除。
2.集合管理
创建集合
在 mongodb 中其实不需要专门创建集合,直接添加文档,mongodb 也会自动生成集合
// 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})
集合列表
show collections // 或 show tables 或 db.getCollectionNames()
删除集合
db.集合名称.drop()
查看集合
db.getCollection("集合")
db.集合名称
查看集合创建信息
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 | 用于嵌入文档, 相当于子属性是另一个 |
Null | 空值,相当于 |
Symbol | 与字符串用法相同,常用于某些使用特殊符号的语言,二进制 |
Date | 用于以 |
Binary data | 二进制数据,常用于保存文件的内容,往往是图片,数据本身。 |
Code | 用于将 JavaScript代码存储到文档中 |
Regular expression | 正则表达式 |
2.添加文档
文档的数据结构和JSON基本一样。所有存储在集合中的数据在内部存储的格式都是BSON格式。
BSON是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
//添加文档
//方式1
db.<集合名称>.insert(<document>) // document就是一个json格式的数据//方式2
db.<集合名称>.insertOne(<document>) // 如果文档存在_id主键为更新数据,否则就添加数据。//方式3
//一次性添加多个文档,多次给同一个集合
db.<集合名称>.insertMany([<document>,<document>,...])
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.删除文档
// 方式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> // 可选参数,抛出异常的级别。}
)
// 添加多条测试数据
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.查询文档
// 获取一条
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()
// 切换数据库
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.比较运算
操作 | 格式 | 语法例子 |
|
等于 |
|
|
|
小于 |
|
|
|
小于或等于 |
|
|
|
大于 |
|
|
|
大于或等于 |
|
|
|
不等于 |
|
|
|
包含 |
|
|
|
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.逻辑运算
|
|
|
|
|
|
|
|
|
|
|
|
// 查询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.排序显示
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,设置值查询部分数据。
// 只显示人名
db.user_list.find({},{'name':1,'_id':0})
9.分页查询
limit方法用于限制返回结果的数量,skip方法用于设置返回结果的开始位置
// 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.更新文档
操作 | 语法 | 说明 |
|
| 更新 |
|
| 更新 |
|
| 移除 |
|
| 给 |
|
| 与 |
|
| 给 |
// 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
from pymongo import MongoClientclient = MongoClient('localhost', 27017) # 连接到本地MongoDB
db = client['py_spider'] # 选择或创建一个数据库
3.文档插入
插入数据时如果集合不存在则新建集合
from pymongo import MongoClientmongo_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()
查询满足条件的多个文档。
# 查询单个文档
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()
更新多个文档。
# 更新单个文档
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()
删除多个文档。
# 删除单个文档
query = {"address": "杭州"}
collection.delete_one(query)# 删除多个文档
query = {"address": {"$regex": "^上"}}
collection.delete_many(query)