MongoDB 入门
认识
MongoDB 是由 C++ 语言编写的,是一个基于分布式文件存储的开源数据库系统
一些概念
QL 术语/概念 | MongoDB 术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB 不支持 | |
primary key | primary key | 主键,MongoDB 自动将 _id 字段设置为主键 |
数据库
数据库名可以是满足以下条件的任意 UTF-8 字符串。
- 不能是空字符串
""
- 不得含有 ' '(空格)、.、$、/、\和\0 (空字符)
- 应全部小写
- 最多 64 字节
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
- admin:从权限的角度来看,这是 "root" 数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
- local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config: 当 Mongo 用于分片设置时,config 数据库在内部使用,用于保存分片的相关信息。
文档
(Document)
文档是一组键值 (key-value) 对 (即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
注意
- 文档中的键 / 值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB 区分类型和大小写。
- 文档不能有重复的键。
- 文档的键是字符串。除了少数例外情况,键可以使用任意 UTF-8 字符。
命名规范
- 键不能含有
\0
(空字符)。这个字符用来表示键的结尾。 .
和$
有特别的意义,只有在特定环境下才能使用。- 以下划线
_
开头的键是保留的 (不严格要求)。
集合
(Collections)
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System) 中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性
数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
Mongo Shell 常用命令
-
显示所有数据库
show dbs
-
显示当前数据库
db
-
连接到指定数据库
use DB_NAME
安装
ubuntu
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list
sudo apt-get update -y
sudo apt-get install -y mongodb-org-tools
sudo apt-get install -y mongodb-mongosh
使用 mongo shell
mongosh
数据库
创建数据库
use DATABASE_NAME
在 MongoDB 中,集合只有在内容插入后才会创建! 也就是说,创建集合 (数据表) 后要再插入一个文档 (记录),集合才会真正创建。
删除数据库
必须先用 use
命令选择要删除的数据库
db.dropDatabase()
删除当前数据库,默认为 test
集合
创建集合
db.createCollection(name, options)
-
name: 要创建的集合名称
-
options: 可选参数,指定有关内存大小及索引的选项
| 字段 | 类型 | 描述 |
| :---------- | :--- | :----------------------------------------------------------- |
| capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 |
| autoIndexId | 布尔 | 3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。 |
| size | 数值 | (可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。 |
| max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
删除
删除集合
必须要先用 use
命令选择待删除集合的数据库
db.collection.drop()
如
db.createCollection("mycol")
db.createCollection("mycol", { capped : true, autoIndexId : true, size :
6142800, max : 10000 } )
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
清空集合
db.collectionName.remove({})
查看现有集合
show collections
文档
插入
插入单个文档
db.collection.insertOne()
- 返回一个文档,其中包含新插入的文档的 _id 字段值
- 如果文档未指定 _id 字段,则 MongoDB 将具有 ObjectId 值的 _id 字段添加到新文档中
参数
- writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
例
db.inventory.insertOne(
{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
插入多个文档
db.collection.insertMany()
参数
- writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
- ordered:指定是否按顺序写入,默认 true,按顺序写入。
例
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
{ item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
如果欲插入到的集合当前不存在,则插入操作将创建该集合。
删除
db.collection.deleteMany()
db.collection.deleteOne()
有例
db.inventory.insertMany( [
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
] );
删除所有文档
db.inventory.deleteMany({})
删除符合条件的文档
指定标准或过滤器,以标识要删除的文档:使用 <field>:<value>
表达式
以下示例从状态字段等于 “A” 的 inventory 集合中删除所有文档
db.inventory.deleteMany({ status : "A" })
下面的示例删除状态为 “D” 的第一个文档
db.inventory.deleteOne( { status: "D" } )
查询
db.collectionName.find(query, projection)
- query :可选,使用查询操作符指定查询条件
- projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)
例
const cursor = db.collection('inventory').find({ status: 'D' });
若要以易读的方式读取数据,可以用 pretty()
:
db.collectionName.find().pretty()
更新
db.collection.updateOne(<filter>, <update>, <options>`)
db.collection.updateMany(<filter>, <update>,<options>`)
db.collection.replaceOne(<filter>, <update>, guo)
有例
db.inventory.insertMany( [
{ item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
{ item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
{ item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }
] );
更新单个文档
db.inventory.updateOne()
下面的示例下面的示例在 inventory 集合上更新项目等于 “paper” 的第一个文档
- 使用
$set
运算符将 size.uom 字段的值更新为 “cm”,将状态字段的值更新为 “P”, - 使用
$currentDate
运算符将 lastModified 字段的值更新为当前日期。 如果 lastModified 字段不存在,则$currentDate
将创建该字段。
db.inventory.updateOne(
{ item: "paper" },
{
$set: { "size.uom": "cm", status: "P" },
$currentDate: { lastModified: true }
}
)
更新多个文档
db.inventory.updateMany()
以下示例更新数量小于 50 的所有文档
db.inventory.updateMany(
{ "qty": { $lt: 50 } },
{
$set: { "size.uom": "in", status: "P" },
$currentDate: { lastModified: true }
}
)
更换整个文档
要替换 _id 字段以外的文档的全部内容,将一个全新的文档作为第二参数传递给 db.collection.replaceOne()
当替换一个文档时,替换文档必须只包含字段 / 值对,即不包括更新操作符表达式
下面的示例替换了 inventory 集合中的第一个文件,其中项为 "paper":
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)
PyMongo
连接
连接数据库
import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)
# or
client = pymongo.MongoClient('mongodb://localhost:27017/')
有密码连接
import pymongo
mongo_client = pymongo.MongoClient('127.0.0.1', 26666)
mongo_auth = mongo_client.admin # admin 为 authenticationDatabase
# or mongo_client['admin']
mongo_auth.authenticate('username', 'password')
判断是否连接成功:
print(mongo_client.server_info()) # 判断是否连接成功
获取 Database 和 Collection
如果没有会自动创建
mongo_db = mongo_client['db_name']
mongo_collection = mongo_db['your_collection']
# or
mongo_db = mongo_client.db_name
mongo_collection = mongo_db.your_collection
插入
插入单条数据
insert_one()
import datetime
info = {
'name' : 'Zarten',
'text' : 'Inserting a Document',
'tags' : ['a', 'b', 'c'],
'date' : datetime.datetime.now()
}
mongo_collection.insert_one(info)
插入多条数据
insert_many()
import datetime
info_1 = {
'name' : 'Zarten_1',
'text' : 'Inserting a Document',
'tags' : ['a', 'b', 'c'],
'date' : datetime.datetime.now()
}
info_2 = {
'name' : 'Zarten_2',
'text' : 'Inserting a Document',
'tags' : [1, 2, 3],
'date' : datetime.datetime.now()
}
insert_list = [info_1, info_2]
mongo_collection.insert_many(insert_list)
插入字符串时间时,mongodb 自动将其转成了 ISOdate 类型,若需要时间在 mongdb 也是字符串类型,只需这样操作即可:
datetime.datetime.now().isoformat()
删除
删除单条数据
delete_one()
若删除条件相同匹配到多条数据,默认删除第一条
mongo_collection.delete_one({'text' : 'a'})
删除多条数据
delete_many()
删除满足条件的所有数据
mongo_collection.delete_many({'text' : 'a'})
更新
更新单条数据
update_one(filter,update,upsert=False)
更新满足条件的第一条数据
- filter:更新的条件
- update : 更新的内容,必须用
$
操作符 - upsert : 默认 False。若为 True,更新条件没找到的情况会插入更新的内容
info = {
'name': '桃子 ',
'text': 'peach',
'tags': [1, 2, 3],
'date': datetime.datetime.now()
}
update_condition = {'name' : 'Zarten_2'} # 更新的条件,也可以为多个条件
# 更新条件多个时,需要同时满足时才会更新
# update_condition = {'name' : 'Pear',
# 'text' : '梨子'}
mongo_collection.update_one(update_condition, {'$set' : info})
更新多条数据
update_many(filter,update,upsert=False)
- filter:更新的条件
- update : 更新的内容,必须用
$
操作符 - upsert : 默认 False。若为 True,更新条件没找到的情况会插入更新的内容
info = {
'name': 'Zarten',
'text': 'a',
'tags': [1, 2, 3],
'date': datetime.datetime.now()
}
update_condition = {'text' : 'a'} # 更新的条件
# 更新条件多个时,需要同时满足时才会更新
# update_condition = {'name' : 'Pear',
# 'text' : '梨子'}
mongo_collection.update_many(update_condition, {'$set' : info})
查询
查询一条数据
find_one()
匹配第一条满足的条件的结果,这条结果以 dict
字典形式返回,若没有查询到,则返回 None
find_condition = {
'name' : 'Banana',
'text' : 'peach'
}
find_result = mongo_collection.find_one(find_condition)
可以通过 projection
参数来指定需要查询的字段,包括是否显示 _id
find_condition = {
'name' : 'Zarten_3',
}
select_item = mongo_collection.find_one(find_condition, projection= {'_id':False, 'name':True, 'num':True})
print(select_item)
可以指定查询范围
import datetime
find_condition = {
'date' : {'$gte':datetime.datetime(2018,12,1), '$lt':datetime.datetime(2018,12,3)}
}
select_item = mongo_collection.find_one(find_condition)
print(select_item)
查询多条数据
find()
返回满足条件的所有结果,返回类型为 Cursor
,通过迭代获取每个查询结果,每个结果类型为 dict
字典
find_condition = {
'name' : 'Banana',
'text' : '香蕉'
}
find_result_cursor = mongo_collection.find(find_condition)
for find_result in find_result_cursor:
print(find_result)
插入文档时会返回一个 _id
,是 ObjectId
类型,可以通过它来查询
若 _id
提供的是 str
类型的,我们需要转成 ObjectId
类型
from bson.objectid import ObjectId
query_id_str = '5c00f60b20b531196c02d657'
find_condition = {
'_id' : ObjectId(query_id_str),
}
find_result = mongo_collection.find_one(find_condition)
print(find_result)