前言
我们对一些关系型数据库肯定不会陌生,比如Oracle、MySQL、SQL Server、SQLite 、PostgreSQL。
什么是SQL?
SQL:结构化查询语言(Structured Query Language)简称SQL,用户使用SQL操作管理数据库系统。
什么是NoSQL?
Not Only SQL 非关系型数据库的意思,它和关系型数据库的区别是:不需要使用SQL去查询数据库内容。
NoSQL没有Table和Filed这些概念,所以数据和数据之间也不存在任何关联关系(1对1、1对多、多对多),每条记录的列可以不一致。
NoSQL数据库的操作都是通过指令/程序语言完成的。
没有了SQL我们如何操作管理MongoDB?
以上我们得知MySQL使用SQL操作管理数据数据库系统。
MongoDB使用JavaScript语法、JSON数据结构来操作管理数据库。
这样以来MongoDB的查询指令和前端JavaScript的数据JSON 进行了数据类型统一
后端程序接收到前端传来的JSON数据,无需复杂处理,直接把JSON数据当做MySQL中的SQL一样去执行就能从数据库中返回查询结果,所以MongoDB很适用于web开发。
MongoDB和Redis的区别?
MongoDB是1个使用C++编写的;1个NoSQL文档型数据库,MongoDB有点像关系型数据,它支持组合/分组聚合查询,而Redis是key,value存储。
MongoDB和Redis都会进行数据的持久化,但Redis会把所有数据加载到内存中,随之数据量的增多,迟早有一天会造成服务器内存的溢出,而MongoDB不会加载所有数据到内存空间。
MongoDB为什么比MySQL更加灵活?
关系型数据库表中的列基本固定很难扩展,而在MobgoDB中存储的文就是各种不同的json对象,所以列可以进行灵活扩展,在{}里加个key的事。
MongoDB为什么比MySQL读写更快?
MongoDB的数据持久化是异步的
MongoDB应用场景?
如果我们要开发的是1个新的web项目,它的功能后期会不断迭代,无法确定1个具体的数据模型不妨试试MongoDB。
我们可以使用MongoDB存储 工单信息、运维审计日志、报警信息,我认为MongoDB适用于无法确定表结构、高并发量、 读写频繁、对事务要求较低的开发场景。
MongoDB中的概念
1.数据库(Database):相当于关系型数据存数据库
2.集合(Collection):数据库中有集合(collection),相当于关系型数据库中表的概念。
3.文档(Document):文档数据库中最小单位,也就是各种各样的json。相当于关系型数据库中记录的概念。
安装MongoDB
1.配置MongoDB的yum源
vim /etc/yum.repos.d/mongodb-org-3.4.repo #添加以下内容: [mongodb-org-3.4] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc #这里可以修改 gpgcheck=0, 省去gpg验证 [root@localhost ~]# yum makecache
2.yum 安装MongoDB
yum -y install mongodb-org
3.配置mongoDB
mkdir -p /data/mongo
chown -R mongod /data/mongo
配置MongoDB的存储和日志路径以及监听端口
# mongod.conf # for documentation of all options, see: # http://docs.mongodb.org/manual/reference/configuration-options/ # where to write logging data. systemLog: destination: file logAppend: true path: /var/log/mongodb/mongod.log # Where and how to store data. storage: dbPath: /data/mongo journal: enabled: true # engine: # mmapv1: # wiredTiger: # how the process runs processManagement: fork: true # fork and run in background pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile # network interfaces net: port: 27017 bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces. #security: #operationProfiling: #replication: #sharding: ## Enterprise-Only Options #auditLog: #snmp:
操作数据库
1.查看现有数据库
> show databases; admin 0.000GB local 0.000GB > show dbs; admin 0.000GB local 0.000GB
2.创建数据库
> use web; switched to db web > show dbs //注意如果数据库中没有Collections数据库不会显示。 admin 0.000GB local 0.000GB
3.创建集合(collection)
> db.createCollection("blogs") { "ok" : 1 } > show dbs admin 0.000GB local 0.000GB web 0.000GB > show collections blogs
4.查看当前数据库的状态
> db.stats() { "db" : "web", "collections" : 1, "views" : 0, "objects" : 0, "avgObjSize" : 0, "dataSize" : 0, "storageSize" : 4096, "numExtents" : 0, "indexes" : 1, "indexSize" : 4096, "ok" : 1 }
5.删库跑路
> db.dropDatabase() { "dropped" : "web", "ok" : 1 } > show dbs admin 0.000GB local 0.000GB > exit bye
操作集合(Collection)
//创建集合
> db.createCollection("blog") //重命名集合
> db.blog.renameCollection("blogs") //展示集合
> show collections //删除集合
> db.blogs.drop(); > show collections > db.dropDatabase();
操作文档
1.insert文档
> db.blogs.insert( ... { ... title:"我的第一篇博客", ... content:"已经开始写博客了好激动呀!!!" ... } ... ); WriteResult({ "nInserted" : 1 })
2.find查看所有文档
> db.blogs.find(); { "_id" : ObjectId("60160d64999c1f14d31784e8"), "title" : "我的第1篇博客", "content" : "已经开始写博客了好激动呀!!!" } { "_id" : ObjectId("60160e74999c1f14d31784e9"), "title" : "我的第2篇博客,我会玩MongoDB啦!好激动呀!!!" } { "_id" : ObjectId("60160f03999c1f14d31784ea"), "title" : "我的第3篇博客,写点什么好呢????", "tag" : "情感" } >
此时我们发现MongoDB的灵活性,以上3条记录的列均不一样,而关系型数据库中所有记录的列是固定和一致的,这些约束限制了我们的数据结构。
3.排序显示
升序sort({ _id:1})
> db.blogs.find({},{_id:0}).sort({_id:1}) { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
降序.sort({ _id:-1})
> db.blogs.find({},{_id:0}).sort({_id:-1}) { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } >
4.修改文档
> db.blogs.update({"tag":"linux"},{$set:{"tag":"Linux"}}); WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blogs.find() { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
5.删除文档
> db.blogs.remove({}) WriteResult({ "nRemoved" : 11 }) > db.blogs.count() 0
MongoDB高级查询
我们在MySQL中常用的组合查询、分组聚合查询在MongoDB中基本都可以支持。
1.根据json对象的key查询
> db.blogs.find("tag":"Linux"); 2021-01-31T10:35:58.917+0800 E QUERY [thread1] SyntaxError: missing ) after argument list @(shell):1:19 > db.blogs.find({"tag":"Linux"}); { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } >
2.大于/小于/等于
> db.blogs.find({"rank":{"$gte":4}}); { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } > db.blogs.find({"rank":{"$gt":4}}); { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } > db.blogs.find({"rank":{"$lte":4}}); { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } > db.blogs.find({"rank":{"$lt":4}}); { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
3.模糊查询
MongoDB的模糊查询支持正则表达式
> db.blogs.find({"title":/n/}); { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } >
查询title包含Python的文档
> db.blogs.find({"title":/Python/}); { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } >
查询title以G开头的文档
> db.blogs.find({"title":/^G/}); { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } >
4.去重复
> db.blogs.distinct("tag"); [ "linux", "Linux", "Python", "Go", "Gin" ] > db.blogs.distinct("title"); [ "如何杀死僵尸进行", "Centos7设置服务开机自启动", "Python引用数据类型", "Python调用Golang", "Golang的指针", "Golang的web框架Gin" ]
5.组合条件查询
之前我们经常在根据用户输入 在前端组织1个搜索条件(json字典)然后传到后端,后端程序再处理json进行SQL拼接,发送给MySQL去执行。
如果使用了MongoDB直接拿着前端传来的JSON数据进行查询即可。所以MongoDB很适合快速开发web应用。
查询title中包含P 和 rank大于等于2的博客。(And)
> db.blogs.find({title:/P/,rank:{$gte:2}}); { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } >
查询title包含O或者rank大于等于2的文档。(Or)
> db.blogs.find({$or:[{title:/O/},{rank:{$gte:2}}]}); { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } >
6.in查询
> db.blogs.find({rank:{$in:[3,4]}}); { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } >
7.分组聚合查询
根据tag进行分组,查询每个tag组的文章个数
> db.blogs.aggregate([{"$group":{"_id":"$tag","数量":{"$sum":1}}}]); { "_id" : "Go", "数量" : 2 } { "_id" : "Gin", "数量" : 1 } { "_id" : "Python", "数量" : 1 } { "_id" : "Linux", "数量" : 2 } >
查看每个tag组rank的最小、最大、平均值
> db.blogs.find() { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" } { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" } > db.blogs.aggregate([{"$group":{"_id":"$tag","平均分":{"$avg":"$rank"},"最大分":{"$max":"$rank"},"最小分":{"$min":"$rank"},"总分":{"$sum":"$rank"},"数量":{"$sum":1}}}]) { "_id" : "Go", "平均分" : 4.5, "最大分" : 5, "最小分" : 4, "总分" : 9, "数量" : 2 } { "_id" : "Gin", "平均分" : 6, "最大分" : 6, "最小分" : 6, "总分" : 6, "数量" : 1 } { "_id" : "Python", "平均分" : 3, "最大分" : 3, "最小分" : 3, "总分" : 3, "数量" : 1 } { "_id" : "Linux", "平均分" : 1.5, "最大分" : 2, "最小分" : 1, "总分" : 3, "数量" : 2 } >
8.分页查询
我们可以使用skip(0).limit(3).sort({_id:1})进行分页查询。
//展示全部数据
> db.blogs.find(); { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
{ "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
//总条目数为6
> db.blogs.find().count();
6
//从0开始向后获取3条数据
> db.blogs.find({},{_id:0}).skip(0).limit(3).sort({_id:1}); { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
//从3开始向后获取3条数据 > db.blogs.find({},{_id:0}).skip(3).limit(3).sort({_id:1}); { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
python操作MongoDB
在日常开发中我们肯定会使用程序去操作数据库而并非命令行。在Python中我们可以使用pymongo模块。
连接数据库
我们使用MySQL的前提是需要创建好数据库和用户然后进行授权。
MongoDB只需要保证MongoDB服务运行正常即可。不需要手动创建数据库和授权。
#Python操作MongoDB的API from pymongo import MongoClient # 创建连接 conn = MongoClient("192.168.56.18", 27017) # 创建数据库对象(没有自动创建) db = conn.web # 创建集合对象(若没有自动创建) blog_set = db.blogs
关闭数据连接
我们在连接完MongoDB之后,最后一定要记得关闭数据连接。
conn.close()
插入数据
# 插入数据到MongoDB # insert_one插入1个文档 blog_set.insert_one({"title": "Linux启动过程", "rank": 18, "tag": "Linux"}) # save插入1个文档:可以使用_id字段,对文档进行修改。 blog_set.save( {"_id": 1, "title": "Linux一切皆文件思想2", "rank": 28, "tag": "Linux"} ) # insert插入1个文档 blog_set.insert({"title": "JavaScript从入门到放弃", "rank": 10, "tag": "JavaScript"}) # 批量插入多个文档1 blog_set.insert( [ {"title": "JavaScript ES6语法", "rank": 18, "tag": "JavaScript"}, {"title": "JavaScript原型", "rank": 10, "tag": "JavaScript"}, {"title": "JavaScript闭包", "rank": 9, "tag": "JavaScript"}, ] ) # insert_many批量插入多个文档2 blog_set.insert_many([ {"title": "Golang的函数", "rank": 10, "tag": "Go"}, {"title": "Golang面向接口编程", "rank": 5, "tag": "Go"}, {"title": "Golang channel", "rank": 6, "tag": "Go"}, ])
操作游标
pymongo调用find()查询方法之后会返回1个游标,我们对这个游标进行操作,可以获取到我们想要的数据。
# 获取1个文档 # print(cursor.next()) # 跳过前2个文档 cursor.skip(2) # 限制获取文档个数 cursor.limit(2) # 文档复合排序 cursor.sort([("_id", -1), ("rank", 1)]) # 查看文档总条目 print(cursor.count())
find()查询操作
find()返回1个游标对象,find()方法查询操作指令和在shell中的指令一致。
# find()查询之后会返回1个游标 cursor = blog_set.find({"rank": {"$gt": 9}}, {'_id': 0}) # 查询所有 for i in cursor: print(i)
find_one()查询
find_one()直接返回1个字典而不是游标对象。
# 查询rank大于10 且tag=Linux的文档 search_dict = {"$and": [{"rank": {"$gt": 10}}, {"tag": "Linux"}]} ret = blog_set.find_one(search_dict, {"_id": 0}) print(ret)
aggregate()分组聚合查询
#聚合查询 ret = blog_set.aggregate([{"$group": {"_id": "$tag", "数量": {"$sum": 1}}}]) for i in ret: print(i) aggregate_search = [{"$group": {"_id": "$tag", "平均分": {"$avg": "$rank"}, "最大分": {"$max": "$rank"}, "最小分": {"$min": "$rank"}, "总分": {"$sum": "$rank"}, "数量": {"$sum": 1}}}] ret = blog_set.aggregate(aggregate_search) for i in ret: print(i) conn.close()
修改操作
upsert=True在查询不到的情况下不去更新而是新增1条新数据
multi=True可以控制修改的范围是所有
# 1.给文档扩展1个域(key) blog_set.update({"title": "Linux一切皆文件思想2"}, {"$set": {"author": "张根"}}) # 2.如果查询不到就新增一条记录:upsert=True来控制 blog_set.update({"title": "Linux一切皆文件思想250"}, {"$set": {"author": "Tom"}}, upsert=True) # 3.multi=True修改多个文档 blog_set.update({"title": "Linux一切皆文件思想250"}, {"$set": {"title": "Linux一切皆文件思想666"}}, multi=True)
删除操作
# 删除所有title=Linux一切皆文件思想666的文档 blog_set.remove({"title": "Linux一切皆文件思想666"}, multi=True)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南