MongoDB
官方文档:https://docs.mongodb.com/
中文文档:https://www.mongodb.org.cn/
mongoDB的生态、理念非常先进而且成熟、但是mongoDB不仅有开源版本,还有企业版本。所以有部分公司比较担心,哪天无法使用mongoDB了,所以也会产生一些替代产品。
DynamoDB : AWS SequoiaDB : 巨杉数据库
基本介绍
MongoDB 是由C++语言编写并基于分布式文件存储的开源数据库,属于NOSQL 。
MongoDB 是一款介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的NOSQL数据库。它面向文档存储,而且安装和操作起来都比较简单和容易,而且它支持各种流行编程语言进行操作,如Python,Node.js,Java,C++,PHP,C#等。
目前在大数据、内容管理、持续交付、移动应用、社交应用、用户数据管理、数据中心等领域皆有广泛被使用。
什么是mongodb?
MongoDB是一个文档数据库,提供好的性能,领先的非关系型数据库。采用BSON存储文档数据(bytes json 二进制json数据)。
BSON()是一种类json的一种二进制形式的存储格式,全称:Binary JSON.
相对于json多了date类型和二进制数组。
为什么用MongoDB?
-
数据结构简单,没有固定的数据结构
-
没有复杂的连接,没有复杂的外键约束
-
深度查询能力,MongoDB支持动态查询,查询api是基于v8引擎(javascript)。
-
容易调试
-
容易扩展
-
不需要转化/映射应用对象到数据库对象
-
使用内部内存作为存储工作区,以便更快的存取数据。
mongodb的应用场景
-
大数据
-
内容管理系统
-
移动端App
-
数据管理
-
日志处理
-
游戏道具处理
MongoDB相对于RDBMS的优势
游戏道具:
[{“id”:1, "name": "衣服", "防御值": 1000}, {“id”:2, "name": "武器", "攻击力": 9999, "攻击距离": 50}, {“id”:3, "name": "鞋子", "移动速度": 1.1, "颜色": "蓝色"},]
id | name | 防御值 | 攻击力 | 攻击距离 | 移动速度 | 颜色 |
---|---|---|---|---|---|---|
2 | 武器 | None | 9999 | 50 | None | None |
1 | 衣服 | 1000 | None | None | None | None |
3 | 鞋子 | None | None | None | 1.1 | 蓝色 |
-
无固定结构 。面向文档,以 JSON 格式的文档保存数据,数据结构由键值(key=>value)对组成。MongoDB 的文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组,单个对象的结构是清晰的。
-
没有复杂的表连接。不需要维护表与表之间的内在关联关系。
-
查询功能强大,丰富的查询语言。MongoDB的查询功能几乎与SQL一样强大,使用基于文档的查询语言,可以对文档进行动态查询,提供丰富的查询操作和索引支持,也有事务操作,可以更快地更稳定的访问数据。(mongoDB4.0以后才真正支持所谓的多文档事务操作)
-
易于调优和扩展。具备高性能、高可用性及可伸缩性等特性
-
应用程序对象与数据库对象天然对应。
-
可分片,对数据存储友好,可以基于内存存储或者硬盘文件存储。
-
任何属性都可以建立索引,而且提供丰富多样的索引。
术语对比
RDBMS | Mongodb | 描述 |
---|---|---|
库(database) | 库(database) | |
表(Table) | 集合(Collection) | |
行/记录(Row/Record) | 文档(Document) | Document就是json结构的一条数据记录 |
列/字段(Column/Field) | 字段/键/域(Field) | 属性字段名 |
主键(Primary Key) | 对象ID(ObjectId) | _id: ObjectId("10c191e8608f19729507deea") |
索引(Index) | 索引(Index) | 都有普通索引, 唯一索引, 主键索引, 联合索引这么区分的 |
MySQL 与 MongoDB 的差别
差别在多方面,例如:数据的表示、查询、关系、事务、模式的设计和定义、速度和性能。
MongoDB 是由 C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的
情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类
似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
MongoDB 是一个面向文档的数据库,目前由 10gen 开发并维护,它的功能丰富齐全,所以完全可以替代 MySQL。
与 MySQL 等关系型数据库相比,MongoDB 的优点如下:
-
弱一致性,更能保证用户的访问速度。
-
文档结构的存储方式,能够更便捷的获取数据。
-
内置 GridFS,支持大容量的存储。
-
内置 Sharding。
-
第三方支持丰富。(这是与其他的 NoSQL 相比,MongoDB 也具有的优势)
-
性能优越
MongoDB 相对于MySQL,它还算比较年轻的一个产品,所以它的问题,就是成熟度肯定没有传统 MySQL那么成熟稳定。所以在使用的时候,第一,尽量使用稳定版,不要在线上使用开发版,这是一个大原则;
另外一点,备份很重要,MongoDB 如果出现一些异常情况,备份一定是要能跟上。除了通过传统的复制的方式来做备份,离线备份也还是要有,不管你是用什么方式,都要有一个完整的离线备份。往往最后出现了特殊情况,它能帮助到你;
另外,MongoDB 性能的一个关键点就是索引,索引是不是能有比较好的使用效率,索引是不是能够放在内存中,这样能够提升随机读写的性能。如果你的索引不能完全放在内存中,一旦出现随机读写比较高的时候,它就会频繁地进行磁盘交换,这个时候,MongoDB 的性能就会急剧下降,会出现波动。
另外,MongoDB 还有一个最大的缺点,就是它占用的空间很大,因为它属于典型空间换时间原则的类型。那么它的磁盘空间比普通数据库会浪费一些,而且到目前为止它还没有实现在线压缩功能,在 MongoDB 中频繁的进行数据增删改时,如果记录变了,例如数据大小发生了变化,这时候容易产生一些数据碎片,出现碎片引发的结果,一个是索引会出现性能问题,另外一个就是在一定的时间后,所占空间会莫明其妙地增大,所以要定期把数据库做修复,定期重新做索引,这样会提升 MongoDB 的稳定性和效率。
基本安装
目前moongDB的最新版本为6.0版本。我们使用ubuntu20.04安装,需要完成以下命令步骤:
# 安装依赖包 sudo apt-get install -y libcurl4 openssl # 关闭和卸载原有的mongodb sudo systemctl stop mongod sudo apt-get purge mongodb* sudo apt-get auto-remove sudo rm -r /var/lib/mongodb sudo rm -r /var/log/mongodb # 导入包管理系统使用的公钥 wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add - # 如果命令执行结果没有显示OK,则执行此命令在把上一句重新执行:sudo apt-get install gnupg # 注册mongodb源 echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list # 更新源 sudo apt-get update # 安装mongodb sudo apt-get install -y mongodb-org # 等待上面的安装过程中,可以先创建mongoDB的数据存储目录 sudo mkdir -p /data/db
终端启动和关闭MongoDB
# 安装完成以后,默认情况下moongDB是没有启动的,需要我们手动加载数据库配置,并启动mongodb sudo systemctl daemon-reload sudo systemctl start mongod # 进入mongo终端: mongosh # 退出mongo终端 .exit # 也可以使用以下命令,退出终端: # quit() # 查看运行状态 sudo systemctl status mongod # 如果mongodb状态为stop,则运行 sudo systemctl enable mongod # 停止mongodb sudo systemctl stop mongod # 重启mongodb sudo systemctl restart mongod
注意:
MongoDB在刚安装完成后,默认是没有进行用户登录的权限验证,默认是不需要输入用户名密码即可登录的,但是注意,mongoDB是提供了用户身份认证功能的。
所以,我们也可以在后面启动用户身份与权限认证,但是必须注意:
mongodb默认是没有管理员账号的,所以要先切换到admin数据库添加管理员账号,再开启权限认证,否则就玩大了。
进入mongo终端的打印效果,如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Current Mongosh Log ID: 63452259fc4d746f759ce077 # log日志的ID Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.6.0 # 终端连接url地址 Using MongoDB: 6.0.2 # mongo的版本号 Using Mongosh: 1.6.0 # mongo交互终端程序的版本号 # 如果要查看更多关于mongoDB交互终端的操作文档如下: For mongosh info see: https://docs.mongodb.com/mongodb-shell/ ------ The server generated these startup warnings when booting # 警告:强烈建议使用XFS文件系统,并使用WiredTiger存储引擎。 (mongoDB的WiredTiger存储引擎类似于 MySQL中的InnoDB存储引擎) # 解释:因为当前ubuntu20.04使用的是ext4文件系统,mongodb官方建议使用XFS文件系统功能更能发挥mongodb的性能,忽略不管 2022-10-11T15:57:00.605+08:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem # 警告:当前mongodb没有为数据库启用访问控制。对数据和配置的读写访问是不受限制的,因此会带来不必要的安全隐患。 # 解释:后面会创建数据库用户采用密码登陆的。暂时不用管 2022-10-11T15:57:01.254+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted # 警告:当前vm虚拟机的进程内存相关参数max_map_count最大内存映射区域数 设置的数值太小了。 # 解析:max_map_count的默认值是65536,设置到262144这个数值即可。 2022-10-11T15:57:01.254+08:00: vm.max_map_count is too low ------ ------ Enable MongoDB's free cloud-based monitoring service, which will then receive and display metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you and anyone you share the URL with. MongoDB may use this information to make product improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring() To permanently disable this reminder, run the following command: db.disableFreeMonitoring() ------ Warning: Found ~/.mongorc.js, but not ~/.mongoshrc.js. ~/.mongorc.js will not be loaded. You may want to copy or rename ~/.mongorc.js to ~/.mongoshrc.js. View Code
开启和关闭云监控平台
// 开启云监控平台[公司一般不会允许内部信息泄露,所以不会开启这个功能] db.enableFreeMonitoring() // 关闭云监控平台 db.disableFreeMonitoring()
成功运行了mongoDB以后,对于mongod和mongosh的区别
mongod是处理MongoDB系统的主要进程。主要负责处理数据请求,管理数据存储和执行后台管理操作。当我们运行mongod命令意味着正在启动MongoDB进程, 并且在后台运行。
mongosh是一个命令行实现的客户端操作mongodb的工具,用于连接一个特定的mongod实例。当我们没有带参数运行mongosh命令它将使用默认的localhost:27017和mongod进行连接。
mongoDB的默认端口:27017
# 查看交互终端的版本 mongosh --version # 或者终端内部使用 version()
基本操作
通用操作
查看帮助文档
help
终端效果:
db 查看当前用户所在数据库的数据库对象 use <db> set current database 切换操作的数据库 show 'show databases'/'show dbs': Print a list of all available databases. 查看当前系统所有的数据库(文档形式显式出来数据库 如果文档是空的不显式) 'show collections'/'show tables': Print a list of all collections for current database. 查看当前数据库所有的数据集合 'show profile': Prints system.profile information. 查看当前系统的环境配置 'show users': Print a list of all users for current database. 查看当前数据库中所有的管理员用户 'show roles': Print a list of all roles for current database. 查看当前数据库中所有的管理员角色 'show log <type>': log for current connection, if type is not set uses 'global' 查看指定日志信息 'show logs': Print all logs. 查看全部日志 it result of the last line evaluated; use to further iterate 查看更多的查询结果,相当于下一页 exit quit the mongo shell 退出终端 sleep Sleep for the specified number of milliseconds 睡眠函数,指定睡眠毫秒 load Loads and runs a JavaScript file into the current shell environment 加载指定js文件的js代码到当前mongo shell交互终端下 cls Clears the screen like console.clear() 清屏 print Prints the contents of an object to the output 打印输出一个终端对象
当前服务器状态
db.serverStatus()
终端效果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{ "host" : "ubuntu", # 主机名 "version" : "6.0.2", # mongodb server 版本 "process" : "mongod", # mongodb进程,主要有mongod和mongos(分片集群中)两种 "pid" : NumberLong(1034), # mongod的pid进程号,可以在linux终端下使用命令 pidof mongod 验证 "uptime" : 105063, # mongodb服务启动的秒数,时间短则表示近期有重启,时间长则表示在稳定运行 "uptimeMillis" : NumberLong(105063193), # mongod服务启动的毫秒数 "uptimeEstimate" : NumberLong(105063), # mongod内部自己计算的启动秒数 "localTime" : ISODate("2020-12-08T16:01:08.230Z"), # 本地时间,相当于 python的 datetime.now() # 客户端连接数相关 "connections" : { "current" : 8, # 当前连接数的编号 "available" : 51192, # 可用最大连接数 "totalCreated" : 1, # 截止目前为止总共历史创建的连接数 "active" : 1, # 还在活跃的连接数,查看并发连接数主要参考这个值 }, # 全局锁相关信息 "globalLock" : { "totalTime" : NumberLong("105063115000"), # mongod启动后到现在的总时间,单位微秒 "currentQueue" : { # 当前等待锁队列 "total" : 0, # 当前全局锁的等待个数 "readers" : 0, # 当前全局读锁等待个数 "writers" : 0 # 当前全局写锁等待个数 }, "activeClients" : { "total" : 0, # 当前活跃客户端的个数 "readers" : 0, # 当前活跃客户端中进行读操作的个数 "writers" : 0 # 当前活跃客户端中进行写操作的个数 } }, "network" : { # 网络相关 "bytesIn" : NumberLong(1611), # 数据库接收到的网络传输字节数 "bytesOut" : NumberLong(51269), # 从数据库发送出去的网络传输字节数 "numRequests" : NumberLong(16), # mongod接收到的总请求次数 }, # 操作计数器 "opcounters" : { "insert" : NumberLong(0), # 本次mongod实例启动至今收到的插入操作总数 "query" : NumberLong(287), # 本次mongod实例启动至今收到的查询总数。 "update" : NumberLong(0), # 本次mongod实例启动至今收到的更新操作总数 。 "delete" : NumberLong(0), # 本次mongod实例启动至今的删除操作总数。 "getmore" : NumberLong(0), # 本次mongod实例启动至今“getmore”操作的总数。 "command" : NumberLong(588)# 本次mongod实例启动至今向数据库发出的命令总数 。 }, # 存储引擎,是MongoDB的核心组件, 负责管理数据如何存储在硬盘(Disk)和内存(Memory)上的组件 # MongoDB 支持多种不同的存储引擎(Storage Engine),MongoDB支持的存储引擎有:WiredTiger,MMAPv1和In-Memory。 # 1. WiredTiger,将数据持久化存储在硬盘文件中;从MongoDB 3.2 版本开始,成为MongDB默认存储引擎 # 2. In-Memory,将数据存储在内存中 # 3. MMAPv1,将数据持久化存储在硬盘文件中; MongoDB 3.2 版本以前的默认存储引擎,类似mysql里面的 MyISAM # WiredTiger 是比MMAPv1更好用,更强大的存储引擎,WiredTiger的写操作会先写入缓存(Cache)中,并持久化到WAL(Write ahead log,写日志),每60s或日志文件达到2GB时会做一次Checkpoint(检查点),将当前数据进行持久化,产生一个新的快照。Wiredtiger连接初始化时,首先将数据恢复至最新的快照状态,然后根据WAL恢复数据,以保证存储可靠性。 # Checkpoint,检测点。将内存中的数据变更冲刷到磁盘中的数据文件中,并做一个标记点。 # 表示此前的数据表示已经持久存储在了数据文件中,此后的数据变更存在于内存(CPU缓存)和WAL日志中. # 是一种让数据库redo(重做)和data(数据)文件保持一致的机制。这种机制,并非Mongodb独有的,mysql中的InnoDB也有。 "storageEngine" : { "name" : "wiredTiger", # 当前mongoDB系统默认的存储引擎是 wiredTiger "supportsCommittedReads" : true, "oldestRequiredTimestampForCrashRecovery" : Timestamp(0, 0), "supportsPendingDrops" : true, "dropPendingIdents" : NumberLong(0), "supportsTwoPhaseIndexBuild" : true, "supportsSnapshotReadConcern" : true, "readOnly" : false, "persistent" : true, "backupCursorOpen" : false }, # 多文档事务,mongodb4.0以后新增特性 "transactions" : { "retriedCommandsCount" : NumberLong(0), "retriedStatementsCount" : NumberLong(0), "transactionsCollectionWriteCount" : NumberLong(0), "currentActive" : NumberLong(0), "currentInactive" : NumberLong(0), "currentOpen" : NumberLong(0), "totalAborted" : NumberLong(0), "totalCommitted" : NumberLong(0), "totalStarted" : NumberLong(0), "totalPrepared" : NumberLong(0), "totalPreparedThenCommitted" : NumberLong(0), "totalPreparedThenAborted" : NumberLong(0), "currentPrepared" : NumberLong(0) }, "locks":{ # 锁相关 }, "mem" : { # 内存相关 "bits" : 64, # 操作系统位数 "resident" : 18, # 物理内存消耗,单位:M "virtual" : 1566, # 虚拟内存消耗,单位:M "supported" : true # 是否显示额外的内存信息 }, }View Code
查看当前db的连接机器地址
db.getMongo()
查看日志
show logs // global // startupWarnings // 如果要查看具体文件的日志。 show log global // global是全局日志,默认保存的日志文件在 /var/log/mongodb/mongod.log // 如果mongoDB无法启动,查看错误就可以来到默认日志文件查看
数据备份与恢复
MongdoDB一共提供了4个命令行工具给我们对数据进行备份与恢复以及导入与导出数据。
备份与恢复操作的数据文件格式是bson格式,二进制文件,不需要进入mongo终端
导入与导出数据的数据文件格式是json格式,文本文档格式,不需要进入mongo终端
准备测试数据
mongoDB终端下进行以下操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 进入mongo交互终端 mongosh use test // mongoDB中可以使用use切换数据库,针对不存在的数据库会自动创建,可通过db在终端查看当前所在数据库 // 声明了一个函数,生成一个指定随机整数,不足10,前面补0 formatnumber = (start, end)=>{ num = Math.round(Math.random() * (end-start)) + start if(num<10){ return "0"+num; }else{ return num; } } // 声明了一个函数,生成具有随机标题 rand_title = ()=>{ num = Math.round( Math.random() * 10 ); num1 = Math.round( Math.random() * 10 ); return [ "赠送礼品-"+num, "购物狂欢-"+num, "随便买买-"+num, "愉快购物-"+num, "赠送礼物-"+num, "商品购买-"+num, "买多送多-"+num, "买年货-"+num, "买买买买-"+num, "充值会员-"+num ][num1]; } // 创建一个函数,循环生成指定的数据 function rand_data(size=200000){ for(var i=0; i<size; i++){ // 往当前数据库的orders集合(相当于mysql的orders数据表) 添加1条数据 db.orders.insertOne({ "order_number": ( "0000000000000000" + i ).substr( String(i).length ), "date": "20"+formatnumber(0,21)+"-"+formatnumber(1,12)+"-"+formatnumber(1,31), "title": rand_title(i), "user_id": parseInt(i/200)+1, "items" :[{ "goods_id" : parseInt(i/200)+1, "goods_number" : formatnumber(2, 10), "price" : formatnumber(50, 1000) },{ "goods_id" : parseInt(i/200)+2, "goods_number" :formatnumber(2, 10), "price" : formatnumber(50, 1000) }] }) // 判断循环过程中,i每逢1000则打印一次数据 if(i%10000==0){ print("已经添加了"+Math.ceil(i/10000)+"万条数据!"); } } } // 调用上面生成测试数据的函数 rand_data() // 查看上面生成的数据 db.orders.find() // 每次显示的数据,mongoDB交互终端默认只会显示20条,所以如果要查看更多,则根据提示输入it可以查看下一页数据。View Code
数据备份
命令格式:
mongodump -h dbhost -d dbname -o dbdirectory
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB服务端地址和端口的简写 | --host=MongoDB地址 --port=端口 |
-d | 备份的数据库名称 | --db=数据库名称 |
-o | 备份数据保存目录所在路径 | 备份数据保存目录需要提前创建 |
例如:备份上面的test数据库
mongodump -h 127.0.0.1:27017 -d test -o /home/moluo/Desktop/ # 删除demo数据库 mongosh use test db.dropDatabase() # 再次查看,可以发现没有任何数据了 db.orders.find()
数据恢复
命令格式:
mongorestore -h dbhost -d dbname --dir dbdirectory --drop
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB服务端地址和端口的简写 | --host=MongoDB地址 --port=端口 |
-d | 恢复的数据库名称 | --db=数据库名称 |
--dir | 备份数据所在目录 | |
--drop | 恢复数据前,先删除MongoDB中的旧数据 |
例如:恢复上面备份的test数据库
mongorestore -h 127.0.0.1:27017 -d test --dir /home/moluo/Desktop/test --drop # 进入数据库查看 use test # 统计当前数据库下orders集合里面所有的文档总数 db.orders.countDocuments()
数据导出
命令格式:
mongoexport -h dbhost -d dbname -c collectionname -o file --type json/csv -f field
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB服务端地址和端口的简写 | --host=MongoDB地址 --port=端口 |
-d | 要导出的数据库名称 | --db=数据库名称 |
-c | 要导出的集合名称 | --collection=集合名称 |
-o | 导出数据保存的文件名 | |
-f | 导出数据的文档字段列表 | 如果不执行-f,则默认导出文档的全部字段 |
--type | 导出数据的文件格式 | 默认是json,也可以是csv,当数据格式为csv时,另需加上-f "字段1,字段2,...." |
例如:导出上面的test数据库的orders集合的所有数据
mongoexport -h 127.0.0.1:27017 -d test -c orders -o /home/moluo/Desktop/test_orders.json --type json
数据导入
命令格式:
mongoimport -h dbhost -d dbname -c collectionname --file filename --type json/csv --headerline -f field
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB服务端地址和端口的简写 | --host=MongoDB地址 --port=端口 |
-d | 要导入的数据库名称 | --db=数据库名称 |
-c | 要导入的集合名称 | --collection=集合名称 |
--file | 导入数据保存的文件名 | |
--type | 导入数据的文件格式 | 默认是json, 也可以是csv,当数据格式为csv时: 1. 需加上-f "字段1,字段2,...." 2. 可以选择加上--headerline,把首行视为导入字段行,不认为是实际数据 |
例如:把上面导出的json文件中的数据,导入到demo数据库的orders集合中
mongoimport -h 127.0.0.1:27017 -d test -c orders --file /home/moluo/Desktop/test_orders.json --type json
用户管理
创建用户
db.createUser(user, pwd, writeConcern)
创建一个数据库新用户用db.createUser()方法,如果用户存在则返回一个用户重复错误。
错误信息:uncaught exception: Error: couldn't add user: User "用户名@数据库" already exists
详细语法:
db.createUser({ user: "<用户名>", pwd: "<密码>", customData: { <any information> }, // 任意内容,主要是为了表示用户身份的相关介绍 roles: [ // 角色和权限分配,一个用户可以绑定多个角色,也就是具备多个角色的权限 { role: "<角色名>", db: "<数据库名>" }, // 也可以直接填写由mongoDB内置的角色,例如: "<role>" ... ] })
注意:
与之前学习的redis或MySQL不同,mongoDB的用户是以数据库为单位来分别建立和管理用户访问控制权限的,每个数据库有属于自己的一个或多个管理员。
管理员可以管理自己的数据库,但是不能直接管理其他数据库,要先在内置数据库admin认证后才可以。
管理员的权限设置包含了2块,分别是角色和权限,由创建用户时通过roles属性进行设置。
内置角色
也叫内建角色,是MongoDB安装以后默认创建提供给我们使用的。
数据库 用户角色:read、readWrite
数据库 管理角色:dbAdmin、dbOwner、userAdmin
集群 管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
备份恢复角色:backup、restore
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
超级用户角色:root
// 超级用户角色 提供了系统超级用户的访问权限
// 有几个角色间接或直接提供了系统超级用户的访问权限(dbAdmin、dbOwner 、userAdmin、userAdminAnyDatabase、dbAdminAnyDatabase)
内置权限
Read:允许用户读取指定数据库 readWrite:允许用户读写指定数据库 dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户 clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。 readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限 readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限 userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限 dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。 root:只在admin数据库中可用。超级账号,擁有超级权限,对所有数据具有超级权限。
给Admin数据库创建账户管理员(相当于给mpongoDB创建了一个HR)
当前账号只能用于管理admin数据库账号,不能进行其他数据库的操作。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 进入/切换数据库到admin中 use admin // 创建账户管理员 // [用户名:admin,密码:123456,数据库:admin,角色userAdminAnyDatabase,表示admin用户在admin数据库中具有超级用户权限] db.createUser({ user: "admin", pwd: "123456", roles: [ {role: "userAdminAnyDatabase",db:"admin"}, ] }); // 终端效果如下: Successfully added user: { "user" : "admin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }View Code
创建超级管理员
当前账号可以进行数据库相关操作。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 进入/切换数据库到admin中 use admin // 创建超级管理员账号 db.createUser({ user: "root", pwd: "123456", roles: [ {role:"root", db:"admin"}, // 也可以这样简写:"root", ] }) // 终端效果如下: Successfully added user: { "user" : "root", "roles" : [ { "role" : "root", "db" : "admin" } ] }View Code
创建用户自己的数据库的角色
帐号是跟着数据库绑定的,所以是什么数据库的用户,就必须先到指定库里授权和验证!!!
一般开发中,往往一个项目就分配一个数据库,并给这个数据库分配一个管理员!!!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 切换数据库,如果当前库不存在则自动创建 use yingmingapp; // 创建管理员用户,为了保证不会报错,所以先删除同名管理员 db.system.users.remove({user:"yingmingapp"}); db.createUser({ user: "yingmingapp", pwd: "123456", roles: [ { role: "dbOwner", db: "yingmingapp"} ] }) // 终端下的效果 /* Successfully added user: { "user" : "yingmingapp", "roles" : [ { "role" : "dbOwner", "db" : "yingmingapp" } ] } */ // 查看当前仓库下的用户 show users; /* 效果: { "_id" : "yingmingapp.yingmingapp", "userId" : UUID("126f2bd2-cddc-450a-9814-3e8937827ab3"), "user" : "yingmingapp", "db" : "yingmingapp", "roles" : [ { "role" : "dbOwner", "db" : "yingmingapp" } ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ] } */ // 也可以在admin库中全局显示所有用户 use admin db.system.users.find()View Code
用户信息
查看当前数据库下的管理用户
只需要切换到对应的库中即可查看
use yingmingapp show users
查看系统中所有的用户
需要切换到admin中使用账号管理员的权限进行操作
use admin // db.auth("root","123456") // 如果开启了mongoDB的访问控制,就需要下用户认证密码才能继续往下操作 db.system.users.find() // 只能在admin数据库中使用。 // db.system.users.find().pretty() // 在mongoDB5.0以前的版本中,pretty表示在返回多个查询结果时,以结构化格式显示数据
删除用户
语法格式:
db.system.users.remove(json条件)
例如,删除上面的用户名为yingmingapp的用户。
// 有多种删除方式,下面是根据user用户名删除用户 use admin db.system.users.deleteOne({user:"yingmingapp"}); // 删除效果: WriteResult({ "nRemoved" : 1 }) // nRemoved 大于0表示成功删除管理员,等于0则表示没有删除。
修改密码
必须切换到对应的数据库下才能给用户修改密码。
所以针对账户管理员或者超级管理员,需要在admin下修改,而其他数据库管理员则必须到对应数据库下才能修改。
db.changeUserPassword("账户名", "新密码");
mongo终端操作:
use yingmingapp // 添加测试账号: db.createUser({ user: "yingmingapp", pwd: "123456", roles: [ { role: "dbOwner", db: "yingmingapp"} ] }) // 注册必须保证有这个管理员 db.changeUserPassword("yingmingapp", "123");
开启账户认证
开启账户认证功能,必须要修改配置文件,然后重启mongoDB才能生效。
sudo vim /etc/mongod.conf // 找到31行附近的 security,去掉左边注释符号(#) security: authorization: enabled :wq // 重启mongdb,配置生效 sudo systemctl restart mongod // 开启了账户认证机制以后,再次进入yingmingapp mongosh use yingmingapp show users // 此处会报错如:uncaught exception: Error: command usersInfo requires authentication db.auth("yingmingapp","123") // 此处认证时填写正确密码: // { ok: 1 } exit mongosh use yingmingapp db.auth("yingmingapp","123456") // 此处认证时填写错误密码: // MongoServerError: Authentication failed. // 注意:如果实现以某个库的账户管理员登录数据库以后,要切换账号操作其他数据库,则必须先退出当前登录状态。
数据库管理
显示所有数据库列表【空数据库不会显示,或者说空数据库已经被mongoDB回收了。】
show dbs show databases
切换数据库,如果数据库不存在则创建数据库。
use <database>
查看当前工作的数据库
db // 是 db.getName() 的简写
删除当前数据库,如果数据库不存在,也会返回{"ok":1}
use <db> // 先切换到要删除的数据库中,然后才能删除数据库 db.dropDatabase()
查看当前数据库状态
test> db.stats() { db: 'test', // 当前数据库名 collections: 1, // 当前数据库中的数据集合数量,相当于mysql的数据表 views: 0, // 当前数据库中的视图数量 objects: 200000, // 当前数据库中的文档数据,相当于mysql中的数据记录 avgObjSize: 235.415035, // 当前数据库中的文档平均大小 dataSize: 47083007, // 当前数据库中的数据总文件大小 storageSize: 10096640, // 存储引擎占据的文件大小 indexes: 1, // 当前数据库中的索引数量 indexSize: 2756608, // 当前数据库中的索引文件大小 totalSize: 12853248, // 数据库中总数据总文件大小 scaleFactor: 1, fsUsedSize: 41576349696, // 文件系统空间占用大小 fsTotalSize: 51989970944, // 文件系统的总占用空间大小 ok: 1 }
在mongoDB中,最重要的核心是文档,如果一个库或者一个库下的集合中的文档全部被删除了,则这个库和这个集合就意味着不存在,会被mongoDB回收删除。
集合管理
mongoDB中的集合有2种:固定集和动态集(数据的大小是固定的还是动态变化的)。
创建集合
一般工作中使用的是动态集(不限制数据流量的),但是在mongoDB优化时,可以对部分数据转换成使用固定集来保存,性能更好,查询速度更快。
在mongodb中如果使用的动态集,其实不需要专门创建集合,直接添加文档,mongodb也会自动生成动态集合的。而固定集需要设置存储的文档上限数量,所以需要提前创建集合。
// name为必填参数,options为可选参数。capped若设置值为true,则size必须也一并设置 db.createCollection( <集合名称>, // 同一数据库中,集合名是唯一的,不能重复创建,否则报错! { capped : <boolean>, // 当前创建的集合是否是固定集,固定集指限制固定数据大小的集合,当数据达到最大值会自动覆盖最早添加的文档内容 size : <bytes_size>, // 如果capped值为True,则表示创建固定集,需要指定固定集合存储的最大字节数,单位:字节数. max : <collection_size> // 如果capped值为True,则表示创建固定集,需要指定固定集合中包含文档的最大数量,单位:字节数 } ); // db.createCollection不填写第二个参数则表示创建的是动态集 // 添加文档到不存在的集合中,mongodb会自动创建动态集合, // db.<集合名称>.insert({"name":"python入门","price" : 31.4}) db.courses.insert({"name":"python入门","price" : 31.4})
固定集的使用操作
固定集一般用于日志,历史记录中。固定集,会因为设置了max或size上限而出现文档被驱逐/出列的情况。后面新增超出部分的数据依旧被添加到集合中,但是最早添加的同等数据数据会被删除掉。
// 创建固定集记录用户的访问足迹,集合名:history > db.createCollection("history", {capped:true, size: 1000000, max: 5, }); { "ok" : 1 } // 可以通过show tables 直接查看当前数据库中所有的集合列表 > show tables; // history // orders // 添加数据到固定集 test > db.history.insert({"name":"python入门","price" : 31.4}) // WriteResult({ "nInserted" : 1 }) test > db.history.insert({"name":"python入门","price" : 32.4}) // WriteResult({ "nInserted" : 1 }) test > db.history.insert({"name":"python入门","price" : 33.4}) // WriteResult({ "nInserted" : 1 }) test > db.history.insert({"name":"python入门","price" : 34.4}) // WriteResult({ "nInserted" : 1 }) test > db.history.insert({"name":"python入门","price" : 35.4}) // WriteResult({ "nInserted" : 1 }) test > db.history.insert({"name":"python入门","price" : 36.4}) // WriteResult({ "nInserted" : 1 }) // 上面一共添加了6条数据到固定集,当时因为创建固定时设置了只允许5条数据, // 所以固定集中针对旧的数据已经删除,只保留最新的5数据。 test > db.history.find() // [ // {_id: ObjectId("634563f011b6d817d0188edd"), name: 'python入门', price: 32.4 }, // {_id: ObjectId("634563f211b6d817d0188ede"), name: 'python入门', price: 33.4 }, // {_id: ObjectId("634563f511b6d817d0188edf"), name: 'python入门', price: 34.4 }, // {_id: ObjectId("634563f711b6d817d0188ee0"), name: 'python入门', price: 35.4 }, // {_id: ObjectId("634563f911b6d817d0188ee1"), name: 'python入门', price: 36.4 } // ]
集合列表
show collections // 或 show tables 或 db.getCollectionNames()
删除集合
删除集合,那么集合中原有的文档数据也被删除掉。
db.集合.drop()
查看集合
// 获取集合的对象 // db.getCollection("集合名称") 或者 db.集合名称 test> db.getCollection("orders") test.orders test> db.orders test.orders
查看集合状态信息
// db.集合名称.stats() db.orders.stats() // 打印效果: { ns: 'test.orders', // 当前集合的命名空间(namespace) size: 47083007, // 当前集合的数据总字节数 count: 200000, // 当前集合的文档数量 avgObjSize: 235, // 当前集合的每个文档平均字节数 capped: false, // 当前集合是否是固定集 }, nindexes: 1, // 当前集合的索引数量,默认如果没有特定设置,默认mongoDB会给文档添加一个_id作为主键。 totalIndexSize: 2756608, // 当前集合的索引的总字节数 totalSize: 12853248, // 当前集合的数据总字节数 indexSizes: { _id_: 2756608 }, // 当前集合的索引的数值上限 }
文档管理
mongodb中,文档也叫 object/document。对应的就是存储的bson数据记录,对应的就是python中的字典或者列表。
mongodb中,允许文档中有各种的自定义字段,每一个字段对应的值也存在不同数据格式,根据不同的格式产生不同的数据类型。
数据类型
Type | 描述 |
---|---|
ObjectID | 用于存储文档的ID,相当于主键,区分文档的唯一字段,mongoDB中就是一个ObjectID对象的返回值。一共由3部分组成:4个字节的时间戳、5个字节的客户端进程生成的随机数、3个字节的增量计数器,一共12字节长度的十六进制数,以此保证了每一个文档的唯一性。 |
String | 字符串是最常用的数据类型,MongoDB中的字符串必须是UTF-8编码。 |
Integer | 整数类型用于存储数值。整数可以是32位,也可以是64位,这取决于你的服务器。 |
Double | 双精度类型,用于存储浮点值,mongodb中没有float浮点数这个说法 |
Boolean | 布尔类型用于存储布尔值(true/ false),注意:是小写的!!! |
Arrays | 将数组、列表或多个值存储到一个键,[] |
Timestamp | 时间戳,用于记录文档何时被修改或创建。Date(),Timestamp(),ISODate() ,默认是ISODate() |
Date | 用于以UNIX时间格式存储当前日期或时间。 |
Object | 用于嵌入文档, 相当于子属性是另一个json文档而已,这种方式就可以实现嵌套。{} |
Null | 空值,相当于 python的None |
Symbol | 与字符串用法相同,常用于某些使用特殊符号的语言,可以理解为一种二进制格式字符串 |
Binary data | 二进制数据,常用于保存文件的内容,往往是图片、音频、视频等数据本身。 |
Code | 用于将JavaScript代码存储到文档中 |
Regular expression | 正则表达式 |
虽然,MongoDB中提供了数据类型,但是mongoDB中对于文档的添加,是不需要预先约束字段值类型的,而是一种自动推断类型。因此,上面的这些类型,我们知道即可。
添加文档
mongodb中,文档的数据结构和 JSON 基本一样。所有存储在集合中的数据在内部存储的格式都是 BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
// 添加文档 // 方式1 db.<集合名称>.insertOne( // 如果文档存在_id主键为更新数据,否则就添加数据。 <document> ) // 方式2: // 一次性添加多个文档, 多次给同一个集合建议使用insertMany比insertOne效率更好 db.<集合名称>.insertMany([ <document>, <document>, ... ])
操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
use test; // 添加一条数据[insert是过去版本的MongoDB提供的添加数据方法] db.users.insertOne({ "name": "laoli", // string "age": 33, // integer "sex": true, // boolean "child": { // Object "name":"xiaohuihui", // string "age":6 // integer } }); // WriteResult({ "nInserted" : 1 }) // mongoDB原则上内置了js解释引擎,所以支持js语法 > db.users.findOne()._id // ObjectId("61552b913ccd8ec29dbf6512") > db.users.findOne().name // laoli // javascrit总可以通过typeof 来查看数据的类型 > typeof db.users.findOne().name // string > typeof db.users.findOne()._id // object > typeof db.users.findOne.sex // boolean > typeof db.users.findOne.age // number > typeof db.users.findOne.child // object > typeof db.users.findOne.child.name // string // 添加一条数据 db.users.insertOne({"name":"xiaozhang","age":18,"sex":true, "money": 300.50}); // { // "acknowledged" : true, // "insertedId" : ObjectId("605021e6d5c7a55cc95c1cb7") // } // 添加多条数据 db.users.insertMany([ {"name":"xiaolan","age":16}, {"name":"xiaoguang","age":16} ]); // { // "acknowledged" : true, // "insertedIds" : [ // ObjectId("60502235d5c7a55cc95c1cba"), // ObjectId("60502235d5c7a55cc95c1cbb") // ] // } db.users.find()View Code
删除文档
// 方式1: 删除一条数据 db.<集合名称>.deleteOne( <filter>, // removed的条件表达式,一般写法:{"字段":{查询器函数:值}},如果不填写删除条件,删除所有文档 ) // 方式2:删除多条数据 db.<集合名称>.deleteMany( <filter>, // removed的条件表达式,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档 )
操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 添加多条测试数据 document1 = {"name":"xiaohei","age":16} document2 = {"name":"xiaobai","age":15} document3 = {"name":"xiaolan","age":18} document4 = {"name":"xiaohui","age":11} document5 = {"name":"xiaoming","age":13} db.users.insertMany([document1,document2,document3,document4,document5]); // 删除满足条件的第一条数据 // mongoDB中的条件格式: {字段名:{$运算符:值} // 条件:{"age":{$eq:16}} 相当于SQL语句的age=16 db.users.deleteOne({"age":{$eq:16}}) db.users.deleteOne({"age":16}); // 等于可以省略不写,相当于 db.users.remove({"age":{$eq:16}}); // 再次 添加多条测试数据 db.users.insertOne({"name": "laozhang", "age": 33, "sex": true, child: {name: "xiaozhang", "age": 4}}) db.users.insertOne({"name": "laowang", "age": 32, "sex": true, child: {name: "xiaowang", "age": 2}}) db.users.insertOne({"name": "laoli", "age": 33, "sex": true, child: {name: "xiaoli", "age": 1}}) db.users.insertOne({"name": "laosun", "age": 34, "sex": true, child: {name: "xiaosun", "age": 7}}) db.users.insertOne({"name": "laozhao", "age": 32, "sex": true, child: {name: "xiaozhao", "age": 6}}) db.users.insertOne({"name": "laoyang", "age": 35, "sex": true, child: {name: "xiaoyang", "age": 4}}) db.users.insertOne({"name": "laohuang", "age": 36, "sex": true, child: {name: "xiaohuang", "age": 3}}) // 删除一条 db.users.deleteOne({"child.age": {$lte: 2}}) // 删除1条 孩子年龄小于或等于2岁的家长数据, // 删除多条 db.users.deleteMany({"child.age": {$lt: 5}}) // 把所有孩子年龄小于5岁的家长数据全部删除View Code
mongoDB中的条件,不仅用于删除数据的条件,也可以是查询或者更新的过滤条件。
查询文档
// 直接显示查询的所有,find和findOne的第二个参数,也是一个json对象,一般称之为字段投影,表示设置是否显示或隐藏指定数据字段。 // 获取一条 db.集合.findOne( <query>, // 查询条件,删除、查询、修改都需要设置条件、条件写法基本一样的。 { // 查询结果的字段投影,用于指定查询结果以后,显示的字段列 <field>: 0, // 隐藏指定字段,例如:"_id":0, <field>: 1, // 显示指定字段,例如:"title":1, .... } ) // 获取多条 db.集合.find( <query>, // 查询条件 { <key>: 0, // 隐藏指定字段,例如:"_id":0, <key>: 1, // 显示指定字段,例如:"title":1, .... } ) // 以易读的方式来格式化显示读取到的数据,只能在find方法后面使用。mongoDB6.0版本以后。默认以易读的方式来格式化显示 db.集合.find().pretty()
操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 切换数据库 use yingmingapp; // 查询整个集合的所有数据 db.users.find() db.users.find({}) // 没有设置任何条件 // 查询一条数据 db.users.findOne() // 获取集合中第一条数据 db.users.findOne({}) // 同上 // 设置字段投影,显示结果中字段列 db.users.find({}, {"child": 0}) // 获取集合中所有数据,并隐藏child属性的数据 db.users.find({}, {"_id": 0, "child": 0}) // 获取集合中所有数据,并隐藏_id 与 child属性的数据 db.users.find({}, {"name": 1}) // 获取集合中所有数据,并只显示name属性与_id主键的字段数据[注意:_id如果不明确隐藏,默认显示的] db.users.find({}, {"name": 1, "_id": 0}) // 获取集合中所有数据,并只显示name属性的字段数据View Code
条件运算符
mongoDB中,条件运算符也叫查询器(query selector)
比较运算
操作 | 格式 | 语法例子 | SQL中的类似语句 |
---|---|---|---|
等于 | 写法1:{<key>:<val> } 写法2:{<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) |
不包含 | {<key>:{$nin:[<val>...]}} |
db.集合.find({"age":{$nin:[1,2,3]}}) |
where age not in (1,2,3) |
终端运行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 添加测试数据 db.users.insertOne({"name": "laozhang", "age": 33, "sex": true, child: {name: "xiaozhang", "age": 4}}) db.users.insertOne({"name": "laowang", "age": 32, "sex": true, child: {name: "xiaowang", "age": 2}}) db.users.insertOne({"name": "laoli", "age": 33, "sex": true, child: {name: "xiaoli", "age": 1}}) db.users.insertOne({"name": "laosun", "age": 34, "sex": true, child: {name: "xiaosun", "age": 7}}) db.users.insertOne({"name": "laozhao", "age": 32, "sex": true, child: {name: "xiaozhao", "age": 6}}) db.users.insertOne({"name": "laoyang", "age": 35, "sex": true, child: {name: "xiaoyang", "age": 4}}) db.users.insertOne({"name": "laohuang", "age": 36, "sex": true, child: {name: "xiaohuang", "age": 3}}) db.users.insertOne({"name": "zhangsanfeng"}) // 查询年龄大于33岁的用户信息 db.users.find({"age":{$gt:33}}) // 查询年龄小于33岁的用户信息 db.users.find({"age":{$lt:33}}) // 查询年龄在32,33,34岁范围里面用户信息 db.users.find({"age":{$in:[32,33,34]}}) // 注意:没有当前字段的文档是不会被通过大于、小于或等于查询出来,因为默认条件不成立 // 所以依靠不存在的字段,是无法使用比较运算符查询出上面添加zhangsanfeng的 db.users.find({"age":{$lt:33}}) db.users.find({"age":{$gte:33}}) db.users.find({"age":{$in:[33]}}) db.users.find({"age":{$nin:[33]}}) // 使用排除范围的方式,可以查询出来。 db.users.find({"age":{$ne: 33}}) // 使用不等于的方式,可以查询出来。View Code
逻辑运算
操作 | 语法 | 语法例子 |
---|---|---|
$and |
写法1:{<key>:<val>,<key>:<val>,...} 写法2:{$and: [{key:{$运算符:<val>}},....]} |
db.集合.find({key1:value1, key2:value2}) |
$or |
{$or: [{<key>: {$运算符:<val>}}, ....]} |
db.集合.find({$or: [{key1: value1}, {key2:value2}]}) |
$and 和$or 组合使用 |
写法1:{<key>:<val>, $or: [{<key>: {<$运算符>:<val>}},...]} 写法2:{$and:[{$or:[{<key>:{<$运算符>:<val>}},..]},$or:[{<key>:{<$运算符>:<val>}},..]}]} |
db.集合.find({key1:value1, $or: [{key1: value1}, {key2:value2}]}) |
$not | {<key>:{$not:{<$运算符>:<val>}}} |
db.集合.find({key1:{$not:{$运算符: val1}}}) |
SQL: (class=301 and sex =true) or (class=302 and sex=false) mongo: { $or: [ {$and: [{class:301}, {sex:true}]}, {$and: [{class:302}, {sex:false}]}, ] }
$and,终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 查询age>34 并且 child.age<5 db.users.find({ $and:[ {"age":{$gt:34}}, {"child.age":{$lt: 5}} ] }) // 简写; db.users.find({"age": {$gt:34}, "child.age": {$lt:5}}) // 查詢age=35,child.age=4 db.users.find({ $and:[ {"age":{$eq:35}}, {"child.age":{$eq: 4}} ] }) // 简写 db.users.find({ $and:[ {"age": 35}, {"child.age": 4} ] }) // 再次简写: db.users.find({ "age": 35, "child.age": 4, })View Code
$or、$and与$or的组合使用,终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 查询age=33或者age=36 db.users.find({ $or: [ {"age":{$eq:33}}, {"age":{$eq:36}} ] }) // 简写: db.users.find({ $or:[ {"age":33}, {"age":36} ] }) // 查询age=33,child.age==5 或者 age=35,child.age==4 db.users.find({ $or: [ {$and: [{age: {$eq: 33}}, {"child.age": {$eq: 5}}]}, {$and: [{age: {$eq: 35}}, {"child.age": {$eq: 4}}]}, ] }) // 简写: db.users.find({ $or: [ {$and: [{age: 33}, {"child.age": 5}]}, {$and: [{age: 35}, {"child.age": 4}]}, ] }) // 再次简写: db.users.find({ $or: [ {age: 33, "child.age": 5}, {age: 35, "child.age": 4}, ] })View Code
$not,终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 查询年龄!=16的 db.users.find({"age":{$not:{$eq:33}}}) // 简写: db.users.find({"age":{$ne: 33}})View Code
其他运算符
操作 | 格式 | 语法例子 | 说明 |
---|---|---|---|
$type | {<key>:{$type: <datetype>}} |
db.集合.find({"name":{$type:'string'}}) |
匹配指定键是指定数据类型的文档 number 数值型 string 字符串 bool 布尔类型 object json文档对象类型 array 数组类型 |
$exists | {<key>:{$exists:<bool>} |
db.集合.find({"title":{$exists:true}}) |
匹配具有指定键的文档,存在指定字段的文档 |
$regex | { <key>:/模式/<修正符>} {<key>:{$regex:/模式/<修正符>}} |
db.集合.find({"name":{$regex:/张$/}}) |
按正则匹配 |
$mod | {<key>: {$mod: [除数, 余数]}} |
db.集合.find({"age":{$mod:[10,0]}}) |
算数运算,取模,语法中举例是age除以10==0 |
终端操作:
db.users.insert({"name":"xiaoming","sex":0,"age":"18", "mobile": "13313621234"}); db.users.insert({"name":"xiaoming","sex":1,"age":18, "mobile": "13441351234"}); db.users.insert({"name":"xiaoming","sex":1,"age":33, "mobile": "13851351234"}); db.users.insert({"name":"xiaoming","sex":0,"age":"33", "mobile": "13881351234", child: {"age": 3, "sex": true}}); db.users.insert({"name":"xiaoming","sex":1,"age":33, "mobile": "10086"}); // $type的使用 db.users.find({"sex":{$type:"number"}}); db.users.find({"sex":{$type:"bool"}}); db.users.find({"age":{$type:"string"}}); // $exists db.users.find({"child":{$exists:true}}); // 查询出存在child字段的数据 // $regex 正则匹配 db.users.find({"mobile":{$regex: /^133/ }}); // 不符合手机号码格式的 db.users.find({"mobile":{$not:{$regex: /1[3-9]\d{9}/ }}}); // $mod 取模,注意:仅针对数值类型,对于字符串是不识别的,所以$mod[3,0],对于 "18"来说,并非整除! db.users.find({"age":{$mod: [3,0] }});
自定义条件查询函数
慎用!效率差,因为需要额外调用javascript执行引擎才过滤,相对效率差。
// 用法1,逻辑比较复杂的情况,可以使用更多的javascript进行运算处理:结果函数结果为true,则当前数据被查询出来。 db.<集合名称>.find({$where: function(){ // this代表的就是查询过程中,被循环的每一条文档数据 return <this.字段> <运算符> <条件值>; }}}); // 用法2,相对没那么复杂的,取函数的返回值作为条件值: db.集合.find({$where: "<this.字段> <运算符> <条件值>"}); // db.集合.find({$where:"this.name=='xiaoming'"});
操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
db.users.find({$where: function(){ return this.age>33 && this.child.age<4; }}); // 把字符串作为代码条件执行,当结果为true,则返回当前符合的数据 db.users.find({$where: "this.age>33 && this.child.age<4"});View Code
排序显示
db.集合.find().sort({<key>:1}) // 升序,默认为升序 db.集合.find().sort({<key>:-1}) // 倒序,
终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
db.users.find().sort({age:-1}); db.users.find().sort({age:-1, sex:1});View Code
字段投影
find()
方法默认将返回文档的所有数据,但是可以通过设置find()
的第二个参数projection,设置值查询部分数据。
语法:
// 获取一条 db.集合.findOne( <query>, // 查询条件 { <key>: 0, // 隐藏指定字段,例如:"_id":0, <key>: 1, // 显示指定字段,例如:"title":1, .... } ) // 获取多条 db.集合.find( <query>, // 查询条件 { <key>: 0, // 隐藏指定字段,例如:"_id":0, <key>: 1, // 显示指定字段,例如:"title":1, .... } )
操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
> db.users.find({"mobile":{$regex:/^133\d{8}$/}},{"_id":0}).sort({"mobile":-1}) { "name" : "xiaoming", "mobile" : "13333355678" } { "name" : "xiaoming", "mobile" : "13333345678" } { "name" : "xiaoming", "mobile" : "13312345678" } > db.users.find({"mobile":{$regex:/^133\d{8}$/}},{"_id":0,"name":0}).sort({"mobile":-1}) { "mobile" : "13333355678" } { "mobile" : "13333345678" } { "mobile" : "13312345678" } > db.users.find({"mobile":{$regex:/^133\d{8}$/}},{"name":1}).sort({"mobile":-1}) { "_id" : ObjectId("60502fb7d5c7a55cc95c1cc4"), "name" : "xiaoming" } { "_id" : ObjectId("60502fb4d5c7a55cc95c1cc3"), "name" : "xiaoming" } { "_id" : ObjectId("60502fb1d5c7a55cc95c1cc2"), "name" : "xiaoming" } > db.users.find({"mobile":{$regex:/^133\d{8}$/}},{"name":1,"_id":0}).sort({"mobile":-1}) { "name" : "xiaoming" } { "name" : "xiaoming" } { "name" : "xiaoming" }View Code
限制与偏移
limit
方法用于限制返回结果的数量
skip
方法用于设置返回结果的开始位置
db.集合.find(...).limit(结果数量).skip(开始下标)
终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
db.users.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5); db.users.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5).skip(0); db.users.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5).skip(5);View Code
更新文档
// 更新数据 db.集合.update( <query>, <update>, { upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入 multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新,设置更新1条还是多条 writeConcern: <document> // 可选参数,抛出异常的级别。 } ) // 更新一条 db.集合.updateOne( <query>, // update的查询条件,一般写法:{"属性":{条件:值}} <update>, // update的更新数据,一般写法 { $set:{"属性":"值",....} } 或者 { $inc:{"属性":"值"} } { upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入 multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新,设置更新1条还是多条 writeConcern: <document> // 可选参数,抛出异常的级别。 } ) // 更新多条 db.集合.updateMany( <query>, // update的查询条件,一般写法:{"属性":{条件:值}} <update>, // update的对象,一般写法 { $set:{"属性":"值"} } 或者 { $inc:{"属性":"值"} } { upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入 multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新 writeConcern: <document> // 可选参数,抛出异常的级别。 } )
update更新运算符[修改器]
操作 | 语法 | |
---|---|---|
$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个数组成员val2。 key2必须是数组。 |
$pull |
db.集合.update({<key1>:<val>}, {$pull:{<key2>:<val2>}}) |
与push相反,给key1=val1的文档中key2列表删除1个指定成员val2 |
$pullAll |
db.集合.update({<key1>:<val>}, {$pullAll:{<key2>:[<val2>,<val3>]}}) | 与$pull作用一样,用于删除多个指定成员 |
$pop |
db.集合.update({<key1>:<val>}, {$pop:{<key2>:<val2>}}) |
给key1=val1的文档中key2列表移除第一个或最后一个成员。 val2只能是1(最后面)或-1(最前面),与python相反 |
终端操作:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// $inc // 把laoli的年龄+10岁 db.users.update({"name":"laoli"},{$inc:{"age":10}}); // 更新一条 db.users.updateMany({"name":"xiaoming"},{$inc:{"age":10}}); // 更新多条 // 把laoli的孩子年龄+10岁 db.users.update({"name":"laoli"},{$inc:{"child.age":10}}); // $set // 如果字段不存在,则新增字段的键值对,如果字段存在,则修改字段的值 //更新laoli的手机号码 db.users.update({"name":"laoli"},{$set:{"mobile":"18012312312"}}); // 更新一条 // 更新laoli孩子的手机号码 db.users.update({"name":"laoli"},{$set:{"child.mobile":"18012312312"}}); // $unset // 移除laoli的性别键值对 db.users.update({"name":"laoli"},{$unset:{"sex":true}}); // $push db.users.update({"name":"laoli"},{$set:{"lve":["TV","game"]}}); db.users.update({"name":"laoli"},{$push:{"lve":"code"}}); // 往列表属性中追加成员 // $addToSet 结合 $each 把一个数组中每一个成员添加到数组中 db.users.update({"name":"laoli"},{$addToSet:{"lve":{$each:["code","music","TV"]}}}); // $pull db.users.update({"name":"laoli"},{$pull:{"lve":"TV"}}); // $pullAll db.users.update({"name":"laoli"},{$pullAll:{"lve":["TV","game"]}}); // $pop db.users.update({"name":"laoli"},{$pop:{"lve":-1}}); // 左边移除列表的第一个成员 db.users.update({"name":"laoli"},{$pop:{"lve":1}}); // 右边移除列表的最后一个成员 // $rename 字段名重命名 db.users.update({"name":"laoli"},{$rename:{"lve":"love"}});View Code
标签:01,users,MongoDB,age,db,find,数据库,name From: https://www.cnblogs.com/erhuoyuan/p/17410847.html