文章目录
MongoDB
- MongoDB是由C++编写的分布式文档数据库
- 内部使用类似于json的bson格式
- 中文手册:https://www.w3cschool.cn/mongodb/
安装
- 下载链接:https://www.mongodb.com/download-center/community
- windows下载官方zip,解压即可使用
组件 | 文件名 |
---|---|
Server | mongod.exe |
Router | mongos.exe, Query Router, Sharding Cluster |
Client | mongo.exe |
MonitoringTools | mongostat.exe, mongotop.exe |
ImportExportTools | mongodump.exe, mongorestore.exe, mongoexport.exe, mongoimport.exe |
MiscellaneousTools | bsondump.exe, mongofiles.exe, mongooplog.exe, mongoperf.exe |
运行
$ D:
$ cd mongodb4/bin
$ ./mongod.exe
// 抛exception in initAndListen: NonExistentPath: Data directory D:\data\db\ not found., terminating异常
$ mongod.exe --help
选项 | 选项说明 |
---|---|
–bind_ip | 绑定以逗号分隔的IP地址;默认localhost |
–bind_ip_all | 绑定所有本地IP地址 |
–port | 端口,默认27017 |
–dbpath | 数据存放的path路径,可以配置;缺省/data/db ,windows下缺省盘符://data/db ; |
–logpath | 指定日志的path路径,替代stdout,可以配置;缺省是控制台打印日志 |
–f | 指定配置文件(yaml格式);可以执行配置文件执行mongod.exe |
注册windows服务
- 选中
我的电脑
,右击查看管理
,选择服务和应用程序
- 点击
服务
,查看windows服务
选项 | 选项说明 |
---|---|
–install | 注册windows服务 |
–serviceName | 服务名称 |
–serviceDisplayName | 服务显示名 |
- Windows注册为服务的命令如下(使用了配置文件)
$ mongode.exe -f "D://mongodb4//db/mongod.yml" --serviceName mongodb -- serviceDisplayName mongo --install
注意:Windows下可以不注册为服务运行MongoDB,且注册服务需要管理员权限
配置文件
- MongoDB配置使用YAML格式
- 嵌套使用缩进完成
- 冒号后面要有空格
- **注意:不支持Tab等制表符,支持空格
参考文档
- Yaml参考:https://www.w3cschool.cn/iqmrhf/dotvpozt.html
- 配置:http://mongoing.com/docs/reference/configuration-options.html
- 参考配置,详细参考配置点击
Core Options
systemLog: # 设置日志输出路径
destination: file # 缺省是输出日志到std; file表示输出到文件
path: "/var/log/mongodb/mongod.log" # 日志文件路径,且文件目录必须存在,文件可以不用存在
logAppend: true # true,在已存在的日志文件EOF处追加;默认false,每次启动服务,重新创建新的日志文件
storage: # 设置数据存放路径
journal:
enabled: true
dbPath: # 设置数据存放的路径,必须指定mongodb的数据目录,且目录必须存在
"D://data/db" # 缺省/data/db
processManagement:
fork: true
net: # 设置MongoDB的ip和port
bindIp: 127.0.0.1 # 设置MongoDB的ip地址
port: 27017 # 设置MongoDB的port,缺省27017
setParameter:
enableLocalhostAuthBypass: false
- 实际配置
systemLog: # 设置日志输出路径
destination: file # 缺省输出日志到std,file表示输出到文件
path: "/var/log/mongodb/mongod.log" # 日志文件路径,文件目录必须存在
logAppend: true # true,表示在已存在的日志文件中E
storage:
dbpath: "D://mongodb/db" # 注意,数据存放的目录必须是db
net: # 设置MongoDB的ip和port
bindIp: 127.0.0.1
port: 27017
客户端
Windows客户端连接
- command(DOS,磁盘操作系统的缩写)中启动MongoDB连接
$ D:
$ cd mongodb4/bin
$ mongd.exe -f D://mongodb/db"
- command中启动Client连接
$ mango.exe
help // 打开帮助
show dbs // 查看当前所有库
use blog
// blog库存在,切换;不存在,创建blog库
// 注意:刚创建的库并不在MongoDB数据库列表中,需要写入数据后才能看到
db // 查看当前数据库
db.users.insert({user:"tom", age:20})
// db代指数据库,users为Colletions名
// 注意:user、age没有加引号,类似于js的对象
Windows可视化工具
- Compass
- 下载地址:https://www.mongodb.com/products/compass
Pycharm插件
- 在settings/plugins中输入mongo,安装Mongo Plugin,完成后重启Pycharm
- 菜单项选择 View/Tool Windows/Mongo Explorer
python连接
- Mongodb官方推荐使用pymongo,参照文档:https://docs.mongodb.com/ecosystem/drivers/pymongo/
$ python -m pip install pymongo
- 缺省安装pymongo 3.10,支持MongoDB2.6+,兼容Python3.4+
- 可以执行安装、更新,详情查看参照文档
Python连接
- MongoDB的连接字符串
"mongodb://username:password@127.0.0.1:27017/test"
from pymongo import MongoClient
from pymongo.results import InsertOneResult
# 客户端连接
# client = MongoClient(host="127.0.0.1", port="27017")
client = MongoClient("mongodb://127.0.0.1:27017")
print(client) # MongoClient对象,连接到数据库
# 既能属性访问,又能向key一样访问,一定实现了魔术方法__getattr__和__getitem__
# db = client.blog
db = client["blog"] # 指定数据库,对应RDBMS的DataBase
print(db) # Database对象,库对象
# users = db["users"]
users = db.users # 指定数据库中的users Collection,对应RDBMS的Table
print(users)
基本概念
- MongoDB中可以创建使用多个库,但有一些数据库名是保留的,可以直接访问这些特殊作用的数据库
- admin:从权限的角度来看,这是"root"数据库
- 需要将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限;
- 一些特定的服务端命令也只能从这个数据库运行,比如列出所有的数据库/关闭服务器
- local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config:当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息
MongoDb和RDBMS的对应关系
MongoDB | RDBMS |
---|---|
Database | Database |
Table | Collection |
Row | Document |
Column | Field |
Join | Embedded Document嵌入文档或Reference引用 |
Primary Key | 主键(MongoDB提供了key为_id) |
文档
- 每一条记录对应一个文档,其格式使用BSON。
- BSON,即Binary JSON
文档
- 文档中,使用键值对
- 文档中,键值对是
有序
的 - 键
- 字符串,
区分大小写
,使用UTF-8字符 - 键不能含有
\0(空字符)
。这个字符用来表示`键字符串的结尾(C、C++语言中,表示字符串的结尾) .
和$
有特别的意义,只有在特定环境下才能使用- 以下划线
_
开头的键是保留的,例如_id
- 字符串,
- 值
- 字符串、32位或64位整数、双精度、时间戳(毫秒)、布尔型、null
- 字节数组、BSON数组、BSON对象
MonogoDB类型
- 类型参考:https://docs.mongodb.com/v3.6/reference/bson-types/
- 常用类型:
- 字符串类型编码为2,别名string
- 数值整形编码为16,别名int
- 长整型编码为18,别名long
- 浮点型编码为1,别名为double
BSON二进制阅读
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1idTGsRF-1578309542614)(D:\1Face_To_Face\爬虫\xmind\BSON.png)]
- 二进制源码查看对应数据库的
db/collection-x-xxx.wt
- 00 00 05 82 d7 35 00 00 00 07 5f 69 64 00 5d 45
- 35表示二进制的长度
- 07表示MongoDB中特殊数据类型ObjectId
- 5f 69 64,为ASCII的_id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UY7zIQMV-1578309542616)(D:\1Face_To_Face\爬虫\xmind\二进制解读.png)]
插入数据
- 单条插入insert_one(self, document, bypass_document_validation=False,session=None)
- document,字典
- 多条插入insert_many(self, documents, ordered=True,
bypass_document_validation=False, session=None)- documents,多个字典组成的列表
from pymongo import MongoClient
from pymongo.results import InsertOneResult, InsertManyResult
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"]
users:Collection = db.users
user1 = {"id":1, "name":"ben", "age":20}
user2 = {"id":257, "name":"jerry", "age":30}
user3 = {"id":258, "name":"tom", "age":49}
user4 = {"id":3, "name":"shiqi", "age":"50", "NAME":'tommy'} # Mongodb中,大小写敏感,且field可以不用一致
# 单条插入
# users.insert(user1) # 已经弃用
one:InsertOneResult = users.insert_one(user1)
print(type(one)) # InsertOneResult类型
print(one) # InsertOneResult实例对象
print(one.inserted_id) # 查看MongoDB提供的_id值,ObjectId对象
# 多条插入
many:InsertManyResult = users.insert_many([user2, user3])
print(type(many)) # InsertManyResult类型
print(many) # InsertManyResult实例
print(many.inserted_ids) # 返回由多个ObjectId对象组成的列表
# 大小写敏感、field可以不用一致
one:InsertOneResult = users.insert_one(user4)
print(one.inserted_id)
ObjectId
- 主键,由MongoDB提供了key,field为_id,Collection为ObjectID
- ObjectID由12个字节组成,每个字节由16进制表示
- 4字节时间戳
- 3字节机器识别码
- 2字节进程ID
- 3字节随机数
from pymongo import MongoClient
from pymongo.results import InsertOneResult, InsertManyResult
from pymongo.collection import Collection
import datetime
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
id = "5e0c085b99ce1f32e8393e98"
# 前4个字节为时间戳
stamp = id[:8]
stamp = int.from_bytes(bytes.fromhex(stamp), 'big') # 从十六进制字符串转为字节,再由字节转为int类型,注意大小端
print(hex(stamp), type(stamp))
t = datetime.datetime.fromtimestamp(stamp) # fromtimestamp将浮点数时间戳转为datetime.datetime类型
print(t, type(t))
import bson
print(bson.ObjectId(id).generation_time) # 返回UTC时间,咱们是东八区,比UTC时间快8小时
查询
- 单值查询:find_one
- 第一参数为filter
- 查询有值,返回字典(带_id);未查询到,返回None
- 多值查询:find
- 第一参数为Collection实例对象self
- 第二参数为filter
- 查询到,返回Cursor对象,可迭代对象;未查询到,返回空
from pymongo import MongoClient
from pymongo.collection import Collection
from bson.objectid import ObjectId
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
# 单值查询
result = users.find_one({"name": "tom"})
print(type(result), result) # 返回查询集,字典
result = users.find_one({'_id': ObjectId('5e0c0766ec444982c52e217d')})
print(type(result), result) # 通过_id查询,返回拆查询集
result = users.find_one({"name": "able"})
print(type(result), result) # 未找到,返回None
# 多值查询
results = users.find() # find什么参数都不写,表示全文搜索
results = users.find({'age': 30}) # 注意:MongDB有数值的概念,所以使用数值
print(type(results)) # Cursot object,可迭代对象
print(results)
for x in results:
print(type(x), x)
查询操作
- 比较
比较符号 | 含义 | 示例 |
---|---|---|
$lt | 小于 | {"age":{"$lt":20}} |
$gt | 大于 | {"age":{"$gt":20}} |
$lte | 小于等于 | {"age":{"$lte":20}} |
$gte | 大于等于 | {"age":{"$gte":20}} |
$ne | 不等于 | {"age":{"$ne":20}} |
$eq | 等于,可以不写 | {"age":{"$eq":20}} |
$in | 在范围内 | {"age":{"$in":20}} |
$nin | 不在范围内 | {"age":{"$nin":20}} |
- 逻辑
逻辑符号 | 含义 | 示例 |
---|---|---|
$and | 与 | {"age":[{"name":"tom"}, {"age":{"$gt":20}}]} {"name":"tom", "age":{"$gt":20}} |
$or | 或 | {"or":[{"name":"tom"}, {"age":{"$gt":20}}]} |
$not | 非 | {'age':{"$not":{"$lte":20}}} |
- 元素
元素符号 | 含义 | 示例 |
---|---|---|
$exists | 判断文档中是否有这个字段,true表示有此字段,False表示无此字段,且将符合条件的document显示 | {"name":{"$exists":True}} |
$type | 判断字段是否是指定的类型,将符合条件的document显示 | {"age":{"$type":16}} |
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
users.delete_many({}) # 删除collection中的所有数据
user1 = {"id":1, "name":"ben", "age":20}
user2 = {"id":257, "name":"jerry", "age":30}
user3 = {"id":258, "name":"tom", "age":49}
user4 = {"id":3, "name":"shiqi", "age":"50", "NAME":'tommy'}
users.insert_many([user1, user2, user3, user4])
print(*users.find(),sep='\n')
print(*users.find({"NAME":{"$exists":True}}), sep='\n')
print('~~~~~~~~~~~~~~~~~~~')
print(*users.find({"age":{"$type":2}}),sep='\n')
- 其他
操作符号 | 含义 | 示例 |
---|---|---|
$regex | 使用正则表达式,对文档中的内容匹配 | {"name":{"$regex":"^t"}} |
$mod | 取模,选择符合取模运算的document | {"age":{"$mod":[10,2]}} ,模10余2的document |
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
users.delete_many({}) # 删除collection中的所有数据
user1 = {"id":1, "name":"ben", "age":20}
user2 = {"id":257, "name":"jerry", "age":30}
user3 = {"id":258, "name":"tom", "age":49}
user4 = {"id":3, "name":"shiqi", "age":50, "NAME":'tommy'}
users.insert_many([user1, user2, user3, user4])
print(*users.find(),sep='\n')
print('~' * 30)
print(*users.find({"name":{"$regex":"^s"}}), sep='\n')
print('*' * 30)
print(*users.find({"age":{"$mod":[2,1]}}), sep='\n')
投影
Cursor的第二参数projection(投影)
- 投影保留
- 元组/列表:将保留的field构建成元组/列表,作为实参传入find的第二参数
- dict:
{"保留field": True, "保留field": 1}
- 投影排除
- dict:
{"排除ield": False, "排除field: 0}
- dict:
注意:投影字典中,要么全是保留,要么全是排除;同时出现保留和排除,抛pymongo.errors
from pymongo import MongoClient
from pymongo.collection import Collection
from bson.objectid import ObjectId
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
# 保留field
results = users.find(filter={'age':{"$gt":20}},projection=("name", "tom"))
results = users.find(filter={"name":"shiqi"}, projection={"name":1, "age":True}) # 保留
# 排除field
results = users.find(filter={"name":"shiqi"}, projection={"name":0, "age":False}) # 排除
# 注意:抛异常
# results = users.find(filter={"name":"shiqi"}, projection={"name":True, "age":False}) # 抛pymongo.errors
for x in results:
print(x)
统计
count_documents(self, filter, session=None, **kwargs)
from pymongo import MongoClient
from pymongo.collection import Collection
from bson.objectid import ObjectId
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
# results = users.find(filter={'age':{"$gt":20}},projection=["name", "aget"]).count() # deprecate,丢弃
print(users.count_documents(filter={"age": {"$gt": 20}}))
排序
sort(self, key_or_list, direction=None)
- self,cursor对象
- key_ro_list,需要排序的field;多个field排序,使用列表
- direction,缺省升序;pymongo.ASCEDING控制升序,pymongo.DESCENDING控制降序
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
from bson.objectid import ObjectId
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
# 升序
results = users.find().sort('age') # 默认升序
results = users.find().sort('age', ASCENDING) # 默认升序
# 降序
results = users.find().sort('age', DESCENDING) # 降序
results = users.find().sort('age', -1) # 降序
for result in results:
print(result)
分页
- limit(),限制查询结果数
- limit()支持负整数,只不过取绝对值,不是取倒数第三个
- skip(),类似于MySQL中的offset
- skip()不支持负整数,抛ValueError
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
# 分页
results = users.find()
print(*list(results), sep='\n')
print('-' * 30)
# skip,跳过,类似于mysql中的offset
results = users.find().skip(1)
print(*list(results), sep='\n')
print('~' * 30)
# limit,限制结果个数
results = users.find().limit(3)
results = users.find().limit(-3)
print(*list(results), sep='\n')
print('*' * 30)
# 先跳过,后限制,limit和skip的先后循序不影响
# results = users.find().skip(2).limit(-2) #
results = users.find().limit(3).skip(2)
print(*list(results), sep='\n')
更新
更新操作符 | 含义 | 示例 |
---|---|---|
$inc | 对给定字段的数值进行增减 | {'$inc':{'age':-5}} |
$set | 设置字段值,如果字段不存在则创建 | {'$set':{'gender':"M"} |
$unset | 移除字段 | {"$unset":{"Name":""}} |
只更新第一个
- update_one
- 第一参数filter
- 第二参数updata,可以使用更新字符串;格式为
{"更新字符串”:{"field":"响应操作"}}
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"tom"}
# result = users.update() # 弃用
result = users.update_one(filter, {"$inc":{"age": 5}}) # 找到tom,且age+5
print(users.find_one(filter))
result = users.update_one(filter, {"$inc":{"age": -5}}) # 找到tom.且age-5
print(users.find_one(filter))
- update_many
- 第一参数filter
- 第二参数updata,可以使用更新字符串;格式为
{"更新字符串”:{"field":"响应操作"}}
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"tom"}
results = users.update_many(filter,{"$set":{"NAME": "Tom"}})
print(*users.find(filter), sep='\n')
替换
- replace_one
- 更新除_id字段外的所有字段
- 更新一个document,即更新一个记录
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"tom"}
users.replace_one(filter, {'id':10, "name":"test", "age": 29})
print(*users.find({"name": "test"}), sep='\n')
删除
删除一个
- delete_one
- 第一参数filter
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"test"}
# users.remove() # 弃用
delete_result = users.delete_one(filter)
print(type(delete_result), delete_result.deleted_count) # delted_count,返回删除的document数量
print(delete_result) # pymongo.results.DeleteResult实例对象
print(*users.find(filter), sep='\n')
删除多个
- delete_many
- 第一参数filter
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"test"}
delete_results = users.delete_many(filter)
print(type(delete_results), delete_results.deleted_count) # delted_count,返回删除的document数量
print(delete_results) # pymongo.results.DeleteResult实例对象
print(*users.find(filter), sep='\n')
删除所有文档
- users.delete_many({})
- 删除collection中的所有数据
- 慎用
users.find(filter), sep=’\n’)
### 删除多个
* delete_many
* 第一参数filter
```python
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.collection import Collection
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["blog"] # 切片访问,魔术方法__getitem__实现
users:Collection = db.users
filter = {"name":"test"}
delete_results = users.delete_many(filter)
print(type(delete_results), delete_results.deleted_count) # delted_count,返回删除的document数量
print(delete_results) # pymongo.results.DeleteResult实例对象
print(*users.find(filter), sep='\n')
删除所有文档
- users.delete_many({})
- 删除collection中的所有数据
- 慎用