MongoDB--基础篇
MongoDB相关概念
业务应用场景
传统的关系型数据库(如MySQL
),在数据操作的“三高”需求以及应对Web2.0
的网站需求面前,显得力不从心。
解释:“三高”需求:
- High performance - 对数据库高并发读写的需求。
- Huge Storage - 对海量数据的高效率存储和访问的需求。
- High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求。
而MongoDB可应对“三高”需求。
具体的应用场景如:
1)社交场景,使用
MongoDB
存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。2)游戏场景,使用
MongoDB
存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。3)物流场景,使用
MongoDB
存储订单信息,订单状态在运送过程中会不断更新,以MongoDB
内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
4)物联网场景,使用
MongoDB
存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。5)视频直播,使用
MongoDB
存储用户信息、点赞互动信息等。
这些应用场景中,数据操作方面的共同特点是:
(1)数据量大
(2)写入操作频繁(读写都很频繁)
(3)价值较低的数据,对事务性要求不高
对于这样的数据,我们更适合使用MongoDB
来实现数据的存储。
📝 什么时候选择MongoDB
在架构选型上,除了上述的三个特点外,如果你还犹豫是否要选择它?可以考虑以下的一些问题:
应用不需要事务及复杂
join
支持新应用,需求会变,数据模型无法确定,想快速迭代开发
应用需要
2000-3000
以上的读写QPS
(更高也可以)应用需要TB甚至 PB 级别数据存储
应用发展迅速,需要能快速水平扩展
应用要求存储的数据不丢失
应用需要99.999%高可用
应用需要大量的地理位置查询、文本查询
如果上述有1个符合,可以考虑
MongoDB
,2个及以上的符合,选择MongoDB
绝不会后悔。
MongoDB简介
MongoDB
是一个开源、高性能、无模式的文档型数据库,当初的设计就是用于简化开发和方便扩展,是NoSQL
数据库产品中的一种。是最像关系型数据库(MySQL)
的非关系型数据库。它支持的数据结构非常松散,是一种类似于
JSON
的 格式叫BSON
,所以它既可以存储比较复杂的数据类型,又相当的灵活。
MongoDB
中的记录是一个文档,它是一个由字段和值对(fifield:value)
组成的数据结构。MongoDB
文档类似于JSON
对象,即一个文档认为就是一个对象。字段的数据类型是字符型,它的值除了使用基本的一些类型外,还可以包括其他文档、普通数组和文档数组。
体系结构
📝 MySQL和MongoDB的对比:
SQL术语概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
嵌入文档 | MongoDB通过嵌入式文档来替代多表连接 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
数据模型
MongoDB
的最小存储单位就是文档(document
)对象,文档(document
)对象对应于关系型数据库的行。数据在MongoDB
中已BSON(Binary-JSON)
文档的格式存储在磁盘上。
BSON(Binary Serialized Document Format)
是一种类json
的一种二进制形式的存储格式,简称Binary JSON
。BSON
和JSON
一样,支持内嵌的文档对象和数组对象,但是BSON
有JSON
没有的一些数据类型,如Date
和BinData
类型。
Bson
中,除了基本的JSON
类型:string,integer,boolean,double,null,array和object,mongo
还使用了特殊的数据类型。这些类型包括date,object id,binary data,regular expression 和code。每一个驱动都以特定语言的方式实现了这些类型,查看你的驱动的文档来获取详细信息。
BSON
数据类型参考列表:
数据类型 | 描述 | 举例 |
---|---|---|
字符串 | UTF-8字符串都可表示为字符串类型的数据 | |
对象id | 对象id是文档的12字节的唯一ID | |
布尔值 | 真或者假:true或者false | {"x":true}+ |
数组 | 值的集合或者列表可以表示成数组 | |
32位整数 | 类型不可用。JavaScript仅支持64位浮点数,所以32位整数会被自动转换 | shell是不支持该类型的,shell中默认会转换成64位浮点数 |
64位整数 | 不支持这个类型。shell会使用一个特殊的内嵌文档来显示64位整数 | shell是不支持该类型的,shell中默认会转换成64位浮点数 |
64位浮点数 | shell中的数字就是这一种类型 | |
null | 表示空值或者未定义的对象 | |
undefifined | 文档中也可以使用未定义类型 | |
符号 | shell不支持,shell会将数据库中的符号类型的数据自动转换成字符串 | |
正则表达式 | 文档中可以包含正则表达式,采用JavaScript的正则表达式语法 | |
代码 | 文档中还可以包含JavaScript代码 | {"x" : function() { /* …… */ }} |
二进制数据 | 二进制数据可以由任意字节的串组成,不过shell中无法使用 | |
最大值/最小值 | BSON包括一个特殊类型,表示可能的最大值。shell中没有这个类型 |
提示:
shell默认使用64位浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
MongoDB的特点
-
高性能:
MongoDB提供高性能的数据持久性。特别是,
对嵌入式数据模型的支持减少了数据库系统上的I/O活动。
索引支持更快的查询,并且可以包含来自嵌入式文档和数组的键。(文本索引解决搜索的需求、TTL索引解决历史数据自动过期的需求、地理位置索引可用于构建各种 O2O 应用)
mmapv1、wiredtiger、mongorocks(rocksdb)、in-memory 等多引擎支持满足各种场景需求。
Gridfs解决文件存储的需求。
-
高可用性:
MongoDB的复制工具称为副本集(replica set),它可提供自动故障转移和数据冗余。
-
高扩展性:
MongoDB提供了水平可扩展性作为其核心功能的一部分。
分片将数据分布在一组集群的机器上。(海量数据存储,服务能力水平扩展)
从3.4开始,MongoDB支持基于片键创建数据区域。在一个平衡的集群中,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片。
-
丰富的查询支持:
MongoDB支持丰富的查询语言,支持读和写操作(CRUD),比如数据聚合、文本搜索和地理空间查询等。
-
其他特点:
如无模式(动态模式)、灵活的文档模型、
MongoDB中的基本概念
📝 数据库
- 一个
mongodb
中可以建立多个数据库。MongoDB
的默认数据库为"db",该数据库存储在data目录中MongoDB
的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
📝 集合
- 集合就是
MongoDB
文档组,类似于RDBMS
(关系数据库管理系统:Relational Database Management System)中的表格。- 集合存在于数据库中,集合没有固定的结构,对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
集合命名的时候应该注意:
- 集合名不能是空字符串""。
- 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
- 集合名不能以"system."开头,这是为系统集合保留的前缀。
- 用户创建的集合名字不能含有保留字符。
📝 文档(document)
是一组键值(key-value)对(即
BSON
)。MongoDB
的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是MongoDB
非常突出的特点。需要注意的是:
- 文档中的键/值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型。
- MongoDB区分类型和大小写。
- MongoDB的文档不能有重复的键。
- 文档的键是字符串。
MongoDB部署
1.下载软件包
# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.1.tgz
2.解压缩
# tar -xvzf mongodb-linux-x86_64-rhel70-4.4.1.tgz
# mv mongodb-linux-x86_64-rhel70-4.4.1 /usr/local/mongodb
3.创建数据目录、日志目录、配置文件存放目录
# mkdir /usr/local/mongodb/{data,conf,log}
4.编辑配置文件
# cat >>/usr/local/mongodb/conf/mongodb.conf<<EOF
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongodb.log
bind_ip=0.0.0.0
port=27017
logappend=1
fork=1
EOF
5.添加环境变量
# vim /etc/profile
export MONGODB_HOME=/usr/local/mongodb
export PATH=$PATH:$MONGODB_HOME/bin
# source /etc/profile
6.启动
# mongod --config /usr/local/mongodb/conf/mongodb.conf
# ps -ef |grep mongo
root 3969694 1 0 10:19 ? 00:01:06 mongod --config /usr/local/mongodb/conf/mongodb.conf
✏️ 停止mongodb
停止服务的方式有两种:快速关闭和标准关闭
1.快速关闭方法(快速,简单,数据可能会出错)
目标:通过系统的kill命令直接杀死进程,杀完要检查一下,避免有的没有杀掉。
通过进程编号关闭节点
# kill -2 3969694
2.标准的关闭方法(数据不容易出错,但麻烦)
目标:通过mongo客户端中的shutdownServer命令来关闭服务
//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
> mongo --port 27017
//#切换到admin库
> use admin
//关闭服务
> db.shutdownServer()
补充
如果一旦是因为数据损坏,则需要进行如下操作(了解):
1.删除lock文件
# rm -f /usr/local/mongodb/data/mongod.lock
2.修复数据
# mongod --repair --dbpath=/usr/local/mongodb/data/
常用命令
MongoDB库操作
📝 MongoDB系统保留库说明:
系统保留数据库:可以直接访问这些有特殊作用的数据库。
- admin:从权限的角度来看,这是"root"数据库
- local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合;
- config:当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
✏️ 选择和创建数据库
> use 数据库名
如果数据库不存在,则创建数据库,否则切换到指定的数据库。
> use articledb
✏️ 查看当前服务器的所有数据库
> show databases
或
> show dbs
✏️ 查看当前正在使用的数据库
> db
✏️ 删除数据库
> db.dropDatabase()
备注:主要用来删除已经持久化的数据库
注意: 要删除哪个数据库,一定要先切换到要删除的数据库中,然后再进行db.dropDatabase()
MongoDB集合操作
✏️ 集合的显示创建
基本语法:
> db.createCollection(name, options)
其中
- name:要创建的集合名称
- options:可选参数,指定有关内存大小及索引的选项(一下为可选参数列表)
options参数如下:
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为true,则创建固定集合,固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当改值为true时,必须指定size参数。 |
autoIndexld | 布尔 | (可选)如果为true,自动在_id字段创建索引。默认为true。 |
size | 数值 | (可选)为固定集合指定一个最大值,以千字节计(KB)。如果capped为true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大值。 |
📝 示例
创建一个集合testcol
> db.createCollection("testcol");
{ "ok" : 1 }
//创建集合student
> db.createCollection("student");
{ "ok" : 1 }
//创建固定大小的集合,创建固定集合mycol,整个集合空间大小6142800KB,文档最大个数为10000个。
> db.createCollection("mycol",{capped:true,size:6142800,max:10000});
{ "ok" : 1 }
> show tables;
mycol
student
testcol
//创建固定大小的集合,创建固定集合mycol02,整个集合空间大小6142800KB,文档最大个数为10000个。
> db.createCollection("mycol02",{capped:true,size:6142800,max:10000, autoIndexId:true});
{
"note" : "The autoIndexId option is deprecated and will be removed in a future release",
"ok" : 1
}
注意 在MongoDB
中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
✏️ 集合的隐式创建
当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合。
✏️ 集合的查看
> show collections
或者
> show tables
✏️ 集合的删除
集合删除语法格式如下:
> db.collection.drop()
或
> db.集合.drop()
如果成功删除选定集合,则drop()方法返回true,否则返回false.
例如:要删除testcol集合
> db.testcol.drop()
true
文档基本CRUD
文档(document)的数据结构和
JSON
基本一样,所有存储在集合中的数据都是BSON
格式。
文档的插入
✏️ 单个文档插入
语法如下:
db.COLLECTION_NAME.insert(document)
示例:
> use testcoll
switched to db testcoll
> db.student.insert({name:"小白",age:18,sdept:"计算机系",sex:"男",createdatetime:new Date()})
WriteResult({ "nInserted" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 18, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
✏️ 批量文档插入
语法如下:
db.COLLECTION_NAME.insertMany([document1, document2,...])
示例:
> db.student.insertMany(
[
{name:"张大仙",age:19,sdept:"计算机系",sex:"男",createdatetime:new Date()},
{name:"李太白",age:17,sdept:"计算机系",sex:"男",createdatetime:new Date()}
]
)
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5fa255ab45dc2c9556990f3f"),
ObjectId("5fa255ab45dc2c9556990f40")
]
}
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 18, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
文档的更新
语法如下:
db.COLLECTION_NAME.update(
<query>{键名:值},
<update>{$set:{键名:值}},
{
upsert:<boolean>,
multi:<boolean>
}
)
参数说明:
query:update的查询条件
update:update的对象和更新的操作符$set,可以理解为sql update查询内set后面的
upsert:可选,意思是,如果不存在update的记录,是否插入。true为插入,默认是false,不插入。
multi:可选,mongodb默认是false,只更新找到的第一条记录,如果为true,就把按条件查出来多条记录全部更新。
示例:
✏️ 修改匹配的第一条记录
> db.student.update(
{sex:"男"},
{$set:{sdept:"前端"}},
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 18, "sdept" : "前端", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
✏️ 修改匹配的所有记录
> db.student.update(
{sex:"男"},
{$set:{sdept:"后端"}},
{multi:true}
)
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 18, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
✏️ 匹配多个条件(同时满足)
> db.student.update(
{sex:"男", name:"小白"},
{$set:{sdept:"计算机系"}},
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 18, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
✏️ 更新多个值
> db.student.update(
{sex:"男", name:"小白"},
{$set:{sdept:"英语系", age:22}},
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 22, "sdept" : "英语系", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
✏️ 多个条件满足其中一个($or)
> db.student.update(
{$or:[{sex:19}, {name:"小白"}]},
{$set:{sdept:"数学系", age:22}},
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa125ec481bd6c96002a80b"), "name" : "小白", "age" : 22, "sdept" : "数学系", "sex" : "男", "createdatetime" : ISODate("2020-11-03T09:42:04.517Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
文档的删除
语法如下:
db.COLLECTION_NAME.remove(
<query>,
{
justOne:<boolean>
}
)
参数说明:
query:(可选)删除的文档的条件,
justOne:(可选)如果设置为true或1,则只删除一个文档,如果不设置该参数,或使用默认值false,则删除所有匹配条件的文档。
示例:
✏️ 删除符合条件的第一条(justOne.true)
> db.student.remove(
{sex:"男"},
{justOne:true}
)
WriteResult({ "nRemoved" : 1 })
> db.student.find()
{ "_id" : ObjectId("5fa255ab45dc2c9556990f3f"), "name" : "张大仙", "age" : 19, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
{ "_id" : ObjectId("5fa255ab45dc2c9556990f40"), "name" : "李太白", "age" : 17, "sdept" : "后端", "sex" : "男", "createdatetime" : ISODate("2020-11-04T07:18:03.528Z") }
✏️ 删除符合条件的所有记录
> db.student.remove(
{sex:"男"}
)
✏️ 删除所有记录
> db.student.remove({})
文档的查询
MongoDB
查询文档使用find()
方法,使用findOne()
查询一条数据
find()
方法以非结构化的方式来显示所有的文档语法格式:
db.COLLECTION_NAME.find(query,projection) 注意: query:可选,使用查询操作符指定查询条件 projection:可选,使用投影操作符指定返回的值 需要以格式化的方式来读取数据,可以使用pretty()方法。
查询前先造几条数据
db.student.insertMany(
[
{name:"张大仙",age:19,sdept:"计算机系",sex:"男",createdatetime:new Date()},
{name:"李太白",age:17,sdept:"计算机系",sex:"男",createdatetime:new Date()},
{name:"黄花",age:18,sdept:"英语系",sex:"女",createdatetime:new Date()},
{name:"菜花",age:20,sdept:"数学系",sex:"女",createdatetime:new Date()},
]
)
基本查询
✏️ 查询student集合中所有的文档
> db.student.find()
{ "_id" : ObjectId("5fa27688b808fba58f5a3a41"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
{ "_id" : ObjectId("5fa27688b808fba58f5a3a42"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
{ "_id" : ObjectId("5fa27688b808fba58f5a3a43"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
{ "_id" : ObjectId("5fa27688b808fba58f5a3a44"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
✏️ 格式化方法显示查询结果
> db.student.find().pretty()
{
"_id" : ObjectId("5fa27688b808fba58f5a3a41"),
"name" : "张大仙",
"age" : 19,
"sdept" : "计算机系",
"sex" : "男",
"createdatetime" : ISODate("2020-11-04T09:38:16.820Z")
}
{
"_id" : ObjectId("5fa27688b808fba58f5a3a42"),
"name" : "李太白",
"age" : 17,
"sdept" : "计算机系",
"sex" : "男",
"createdatetime" : ISODate("2020-11-04T09:38:16.820Z")
}
{
"_id" : ObjectId("5fa27688b808fba58f5a3a43"),
"name" : "黄花",
"age" : 18,
"sdept" : "英语系",
"sex" : "女",
"createdatetime" : ISODate("2020-11-04T09:38:16.820Z")
}
{
"_id" : ObjectId("5fa27688b808fba58f5a3a44"),
"name" : "菜花",
"age" : 20,
"sdept" : "数学系",
"sex" : "女",
"createdatetime" : ISODate("2020-11-04T09:38:16.820Z")
}
✏️ 条件过滤查询
> db.student.find({sex:"男"})
{ "_id" : ObjectId("5fa27688b808fba58f5a3a41"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
{ "_id" : ObjectId("5fa27688b808fba58f5a3a42"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
✏️ 查询一条记录
> db.student.findOne()
{
"_id" : ObjectId("5fa27688b808fba58f5a3a41"),
"name" : "张大仙",
"age" : 19,
"sdept" : "计算机系",
"sex" : "男",
"createdatetime" : ISODate("2020-11-04T09:38:16.820Z")
}
条件查询
✏️ 多个条件同时满足查询 $and
db.COLLECTION_NAME.find({K1:V1,K2:V2,K3:V3...})
或者
db.COLLECTION_NAME.find({$and:[{K1:V1},{K2:V2},{K3:V3}...]})
示例:
# 查询年龄为19,而且性别为男的学生
> db.student.find({age:19,sex:"男"})
{ "_id" : ObjectId("5fa27688b808fba58f5a3a41"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
> db.student.find({$and:[{age:19},{sex:"男"}]})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 多个条件只是满足其中一个 $or
db.COLLECTION_NAME.find({$or:[{K1:V1},{K2:V2},{K3:V3}...]})
示例:
# 查询年龄是19或者为英语系的学生
> db.student.find({$or:[{age:19},{sdept:"英语系"}]})
{ "_id" : ObjectId("5fa27688b808fba58f5a3a41"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
{ "_id" : ObjectId("5fa27688b808fba58f5a3a43"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T09:38:16.820Z") }
✏️ 根据数据类型来匹配对应的结果$type
db.COLLECTION_NAME.find({KEY:{$type:数字或者数据类型}})
$tpye
操作符,MongoDB
中可以使用的类型如下表所示:
类型 | 数字 | 备注 |
---|---|---|
Double | 1 | |
String | 2 | |
Object | 3 | |
Array | 4 | |
Binary data | 5 | |
Undefined | 6 | 已废弃 |
Object id | 7 | |
Boolean | 8 | |
Date | 9 | |
Null | 10 | |
Regular Expression | 11 | |
JavaScript | 13 | |
Symbol | 14 | |
JavaScript (with scope) | 15 | |
32-bit integer | 16 | |
Timestamp | 17 | |
64-bit integer | 18 | |
Min key | 255 | Query with -1 |
Max key | 127 |
示例:
# 这里先插入一条数据进行测试
> db.student.insert({name:12,age:28,sdept:"体育系",createdatetime:new Date()})
WriteResult({ "nInserted" : 1 })
# 查询名字类型为Double类型的学生
> db.student.find({name:{$type:1}})
{ "_id" : ObjectId("5fa36936bde0f17be2c81931"), "name" : 12, "age" : 28, "sdept" : "体育系", "createdatetime" : ISODate("2020-11-05T02:53:42.760Z") }
✏️ 读取指定数量的数据记录limit()
db.COLLECTION_NAME.find().limit(NUMBER)
NUMBER:表示记录条数,默认值为20
示例:
# 查询性别为男学生前2条记录
> db.student.find({sex:"男"}).limit(1)
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 查询出来的记录,跳过指定数量的前多少条记录skip()
db.COLLECTION_NAME.find().skip(NUMBER)
或者
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
备注:skip(NUMBER)中的NUMBER默认值为0
示例:
# 查询所有的性别为男的学生信息并跳过第一条记录
> db.student.find({sex:"男"}).skip(1)
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
# 查询前两条性别为男的学生信息,跳过第一条记录
> db.student.find({sex:"男"}).limit(2).skip(1)
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 对查询出来的记录进行排序 sort()
db.COLLECTION_NAME.find().sort({key:1})
或者
db.COLLECTION_NAME.find().sort({key:-1})
备注:sort()方法可以通过参数指定排序的字段,并使用1和-1来指定排序的方式,其中1为升序排列,而-1为降序排列。
示例:
# 查询所有学生信息,按照年龄升序排列
> db.student.find().sort({age:1})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa36936bde0f17be2c81931"), "name" : 12, "age" : 28, "sdept" : "体育系", "createdatetime" : ISODate("2020-11-05T02:53:42.760Z") }
# 查询所有学生信息,按照年龄降序排列
> db.student.find().sort({age:-1})
{ "_id" : ObjectId("5fa36936bde0f17be2c81931"), "name" : 12, "age" : 28, "sdept" : "体育系", "createdatetime" : ISODate("2020-11-05T02:53:42.760Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
比较查询
✏️ 大于查询 $gt
db.COLLECTION_NAME.find({KEY:{$gt:value}})
示例:
# 查询年龄大于17的学生
> db.student.find({age:{$gt:17}})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 小于查询$lt
db.COLLECTION_NAME.find({KEY:{$lt:value}})
示例:
# 查询年龄小于20的学生
> db.student.find({age:{$lt:20}})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 大于等于查询 $gte
db.COLLECTION_NAME.find({KEY:{$gte:value}})
示例:
# 查询年龄大于等于17的学生
> db.student.find({age:{$gte:17}})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 小于等于查询 $lte
db.COLLECTION_NAME.find({KEY:{$lte:value}})
示例:
# 查询年龄小于等于20的学生
> db.student.find({age:{$lte:20}})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20, "sdept" : "数学系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
✏️ 不等于查询 $ne
db.COLLECTION_NAME.find({KEY:{$ne:value}})
示例:
# 查询年龄不等于20的学生
> db.student.find({age:{$ne:20}})
db.student.find({age:{$ne:20}})
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17, "sdept" : "计算机系", "sex" : "男", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18, "sdept" : "英语系", "sex" : "女", "createdatetime" : ISODate("2020-11-04T12:25:49.893Z") }
综合示例:
# 查询年龄在17~19之间的学生
> db.student.find({age:{$gt:17,$lt:19}})
# 查询年龄小于18,大于19的学生
> db.student.find({$or:[{age:{$lt:18}},{age:{$gt:19}}]})
查询已什么开头
格式如下:
db.COLLECTION_NAME.find({<key>:/^value/})
参数说明:
key:要查询的字段的名称
value:检查key字段的值中是否以value开始,格式:/^value/,斜杠“/”和“^”不能省略
示例:
rs0:PRIMARY> db.person.find({cid:/^512721/})
{ "_id" : ObjectId("5f0d09c4fc3df4986e62930c"), "cid" : "5127xxxxxx114702", "name" : "xxx", "createtime" : NumberLong(1594689988), "updatetime" : NumberLong(1604285711), "cid_type" : "10" }
查询某个字段总是否包含另一个值
格式如下:
db.COLLECTION_NAME.find({<key>:/value/})
参数说明:
key:要查询的字段的名称
value:查询key字段的值中是否包含着value的值,格式:/value/,前后的两个斜杠“/”不能省略
示例:
rs0:PRIMARY> db.person.find({name:/刘备/})
{ "_id" : ObjectId("5eb3e60ec158d2459d85aaab"), "cid" : "4208xxxx319", "name" : "刘备", "createtime" : NumberLong(1588848142), "updatetime" : NumberLong(1595218336), "cid_type" : "10" }
{ "_id" : ObjectId("5f1d4d75c158d2459d912d75"), "cid" : "4290xxxxx96", "name" : "刘备", "createtime" : NumberLong(1595755893), "updatetime" : NumberLong(1595755893), "cid_type" : "10" }
{ "_id" : ObjectId("5f0e542519c15a619088adf3"), "cid" : "510xxxxxx21", "name" : "徐刘备", "createtime" : NumberLong(1594774565), "updatetime" : NumberLong(1604016893), "cid_type" : "10" }
聚合查询
MongoDB
中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。
格式如下:
db.COLLECTION_NAME.aggregate([
{
管道:{聚合操作表达式}
}
])
管道:就是把找到的数据进行过滤的操作,常用的管道符如下表
管道符 | 描述 |
---|---|
$project |
修改输入文档的结构。可以用来重命名、增加或删除域 |
$match |
用于过滤数据,只输出符合条件的文档。$match 使用MongoDB 的标准查询操作 |
$limit |
用来限制MongoDB 聚合管道返回的文档数 |
$skip |
在聚合管道中跳过指定数量的文档,并返回余下的文档 |
$group |
将集合中的文档分组,可用于统计结果 |
$sort |
将输入文档排序后输出 |
常用聚合表达式
表达式 | 描述 |
---|---|
$sum |
计算总和 |
$avg |
计算平均值 |
$min |
获取集合中所有文档对应值的最小值 |
$max |
获取集合中所有文档对应值的最大值 |
✏️ 分组$group
db.集合名字.aggregate([
{
$group:{_id:"$字段名",聚合函数的别名:{聚合表达式:"$字段名"}}
}
])
示例:
# 统计学生信息男生和女生的总年龄
> db.student.aggregate([
{
$group:{_id:"$sex",成绩总和:{$sum:"$age"}}
}
])
{ "_id" : "女", "成绩总和" : 38 }
{ "_id" : "男", "成绩总和" : 36 }
# 统计学生信息男生和女生各有多少人
> db.student.aggregate([
{
$group:{_id:"$sex",总人数:{$sum:1}}
}
])
{ "_id" : "女", "总人数" : 2 }
{ "_id" : "男", "总人数" : 2 }
//备注:$sum:1 等于MySQL的count(*) 统计总的记录数
# 求学生的总数和平均年龄
> db.student.aggregate([
{
$group:{_id:null,人数:{$sum:1},平均年龄:{$avg:"$age"}}
}
])
{ "_id" : null, "人数" : 4, "平均年龄" : 18.5 }
# 求男生或者女生的总数和平均年龄
> db.student.aggregate([
{
$group:{_id:"$sex",人数:{$sum:1},平均年龄:{$avg:"$age"}}
}
])
{ "_id" : "女", "人数" : 2, "平均年龄" : 19 }
{ "_id" : "男", "人数" : 2, "平均年龄" : 18 }
# 查询男生和女生的人数,按人数升序排列
> db.student.aggregate([
{
$group:{_id:"$sex",总人数:{$sum:1}}
},
{
$sort:{总人数:1}
}
])
# 查询年龄小于等19,只看两条记录
> db.student.find({age:{$lte:19}}).limit(2) #普通方法
# 管道的方法
> db.student.aggregate([
{
$match:{age:{$lte:19}}
},
{$limit:2}
])
# 查看男生的最大年龄
> db.student.aggregate([
{
$match:{sex:"男"}
},
{
$group:{_id:"$sex", 最高分:{$max:"$age"}}
}
])
# 修改文档结构,只含有_id,name,age
> db.student.aggregate([
{
$project:{name:1,age:1}
}
])
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4b"), "name" : "张大仙", "age" : 19 }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4c"), "name" : "李太白", "age" : 17 }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4d"), "name" : "黄花", "age" : 18 }
{ "_id" : ObjectId("5fa29dcd8b194ee77bc32b4e"), "name" : "菜花", "age" : 20 }
//备注:在$project,字段名:1 ---->获取该字段的所有内容
//等于MySQL中的 select name,age from student;
去重统计查询
根据指定字段进行去重,然后统计总数
> db.person.aggregate([
{"$group": {"_id": "$cid"}},
{"$group": {"_id": null, "counts": {"$sum": 1}}}
])
# 说明:
第一个group进行分组,中的"_id"指定需要去重的字段名称,这里根据cid进行去重
第二个group进行统计,中的"_id"可为空,也可为null
常用命令总结
# 选择切换数据库:
use DB_NAME
# 插入数据:
db.COLLECTION_NAME.insert({bson数据})
# 查询所有数据:
db.COLLECTION_NAME.find()
# 格式化显示查询的数据:
db.COLLECTION_NAME.find().pretty()
# 条件查询数据:
db.COLLECTION_NAME.find({K1:V1,K2:V2...})
# 查询符合条件的第一条记录:
db.COLLECTION_NAME.findOne({K1:V1,K2:V2...})
# 查询符合条件的前几条记录:
db.COLLECTION_NAME.find({K1:V1,K2:V2...}).limit(条数)
# 查询符合条件的跳过的记录:
db.COLLECTION_NAME.find({K1:V1,K2:V2...}).skip(条数)
# 查询满足多个条件中任意条件的记录:
db.COLLECTION_NAME.find({$or:[{K1:V1},{K2:V2},{K3:V3}...]})
# 对查询结果进行升序排序
db.COLLECTION_NAME.find().sort({kEY:1})
# 对查询结果进行降序排序
db.COLLECTION_NAME.find().sort({kEY:-1})
# 大于查询
db.COLLECTION_NAME.find({KEY:{$gt:value}})
# 小于查询
db.COLLECTION_NAME.find({KEY:{$lt:value}})
# 大于等于查询
db.COLLECTION_NAME.find({KEY:{$gte:value}})
# 小于等于查询
db.COLLECTION_NAME.find({KEY:{$lte:value}})
# 不等于查询
db.COLLECTION_NAME.find({KEY:{$ne:value}})
# 查询大于小于之间的数据记录
db.COLLECTION_NAME.find({KEY:{$gt:NUMBER,$lt:NUMBER}})
# 查询小于多少,或者大于多少的数据
db.COLLECTION_NAME.find({$or:[{KEY:{$lt:NUMBER}},{KEY:{$gt:NUMBER}}]})
# 统计查询
db.COLLECTION_NAME.find().count()
# 查询已什么开头
db.COLLECTION_NAME.find({<key>:/^value/})
或者:
db.COLLECTION_NAME.find({<key>: {"$regex": "^value"}})
# 查询某个字段总是否包含另一个值
db.COLLECTION_NAME.find({<key>:/value/})
# 根据指定字段去重并统计总数
db.person.aggregate([
{"$group": {"_id": "$cid"}},
{"$group": {"_id": null, "counts": {"$sum": 1}}}
])