1-MongoDB - 基础操作
MongoDB默认的库
当你登录到客户端,默认进入的是test库,另外,它还有三个默认库。
[mongod@cs mongodb]$ mongo
db // 等价于 select database();
db.getName() // 也是查看当前所在的数据库
show dbs; // 等价于 show databases;
admin 0.000GB
config 0.000GB
local 0.000GB
其中:
- test,登录时默认进入的库。
- admin,系统预留库,是MongoDB系统管理用。
- local,本地预留库,存储关键日志。
- config,MongoDB配置信息库。
当你use
到某个库中,可以通过下面两个命令来查看所有的集合:
use admin
show tables;
show collections;
另外,你可以使用use
到一个不存在的库,而只有真正的在这个库中添加数据时,这个库才被创建。
MongoDB命令的种类
在MongoDB中,命令是以函数形式调用的,而我们可以将大部分的命令都划分为三大类:
db
,对象(库,集合,文档)相关命令。rs
,复制级相关命令。sh
,分片集群相关。
上面的几个命令都支持tab键,比如db.
按两下tab,就返回所有db类的命令;或者使用db.help()
返回所有db命令的帮助信息。
本篇来学习MongoDB对象相关的操作,所谓的对象操作,就是对库、集合、文档的操作,而开发中,这些从操作通常都会由开发人员通过某门语言连接到MongoDB再进行操作,所以,这里只做相关操作的示例。
数据库操作
MongoDB的库操作,非常简单,记住下面这两条命令就好了。
use test // 切换到指定库
db.dropDatabase() // 删除当前库,如果库不存在也会返回 { "ok" : 1 }
{ "ok" : 1 }
// 查看当前数据库
db
db.getName()
// 查看当前数据状态信息
db.stats()
{
"db" : "test",
"collections" : 0,
"views" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 0,
"numExtents" : 0,
"indexes" : 0,
"indexSize" : 0,
"fileSize" : 0,
"fsUsedSize" : 0,
"fsTotalSize" : 0,
"ok" : 1
}
你或许有点迷惑,创建库操作怎么没有?稳住,后续会说。
集合操作
关于集合的常用的命令:
// 切换到库 t1 中,注意,此时 t1 还未真正的创建
use t1
// 创建集合 s1,此时,t1已存在
db.createCollection('s1')
{ "ok" : 1 }
// 添加文档时,如果库和集合不存在,MongoDB会自动创建库和集合,然后再添加文档
db.s2.insert({"name": "张开"})
// 返回集合 s1 中文档的个数
db.s1.count()
0
// 集合中索引+数据压缩存储之后的大小
db.s1.totalSize()
8192
// 删除集合
db.s1.drop()
// 返回当前数据库下所有集合
db.getCollectionNames()
show collections
show tables
文档操作
文档操作就是如何在集合中管理文档了。
MongoDB中的文档,可以理解为json类型的对象,集合中的每个文档对象都是独立的,并且MongoDB会为每个文档建立索引加速查询。
添加文档
// 添加数据 方式1 先创建集合,在使用集合的inset方法插入文档
db.createCollection('s2')
db.s2.insert({"name": "zhangkai", "age": 18})
db.s2.insert({"name": "likai", "age": 20})
// 添加数据 方式2 当插入一篇文档的时候,集合会自动地创建
db.s3.insert({"name": "wangkai", "age": 22})
// 在介绍两个添加文档的方法
// 一次添加一条
db.s4.insertOne({"name": "zhangkai1", "age": 18})
// 一次添加多条
db.s4.insertMany([
{"name": "zhangkai2", "age": 18},
{"name": "zhangkai3", "age": 19},
])
// 添加数据 方式3 批量录入(用的较多)
for(i=0;i<1000;i++){db.s4.insert({"num": i, "k": "v", "date": new Date()})}
WriteResult({ "nInserted" : 1 })
// 可以通过下面的设置,控制每页显式得结果条数,然后输入it翻页
DBQuery.shellBatchSize=50
另外,需要注意的是,如果在添加文档时没有指定_id
,MongoDB会自动为这篇为文档生成一个_id
作为索引:
db.s5.insertMany([
{"id": 1, "name": "zhangkai2", "age": 18},
{"_id": 2, "name": "zhangkai3", "age": 19},
])
db.s5.find()
{ "_id" : ObjectId("600831c86b2f4b4cf9a9e929"), "id" : 1, "name" : "zhangkai2", "age" : 18 }
{ "_id" : 2, "name" : "zhangkai3", "age" : 19 }
如上,第一篇文档的id
字段只是普通的字段,MongoDB会自动生成一个_id
字段作为索引;第二篇文档我们手动指定了_id
,那么MongoDB就不会再创建_id
字段了。在实际开发中,要尽量避免这两种情况同时出现。
查询文档
查询可以分为,基本查询和复杂查询,复杂查询也就是搭配运算符进行条件过滤查询。
基本查询
查询文档通常使用下面两个方法:
// 查询所有文档
db.s4.find(<查询条件>, <其他过滤条件>)
// 查询一篇文档
db.s4.findOne(<查询条件>, <其他过滤条件>)
来看具体怎么使用:
// find用法
db.s4.find() // 无条件则查询所有文档
db.s4.find({}) // {} 相当于无条件,也返回所有文档
db.s4.find({"name": "zhangkai1"}) // 按条件查询
{ "_id" : ObjectId("600830666b2f4b4cf9a9e926"), "name" : "zhangkai1", "age" : 18 }
// 其他过滤条件中,可以指定返回结果,都返回哪些字段,或者哪些字段不返回
// 0:不返回指定字段
// 1:返回指定字段
db.s4.find({"name": "zhangkai1"}, {"name": 1, "age": 1, "_id": 0})
{ "name" : "zhangkai1", "age" : 18 }
// findOne用法
db.s4.findOne() // 返回所有结果的第一条
db.s4.findOne().pretty() // 格式化返回
db.s4.findOne({"name": "zhangkai1"}, {"name": 1, "age": 1, "_id": 0}) // 根据条件过滤
{ "name" : "zhangkai1", "age" : 18 }
对于返回结果字段的过滤,我们一般称之为投影。
sort和limit
// 排序, 1:升序,默认升序 -1:降序
db.s4.find().sort({"age": 1})
db.s4.find().sort({"age": -1})
// 多条件排序,以 age 进行降序排序,如果遇到 age 相同的,以 _id 升序排序
db.s4.find().sort({"age": -1, "_id": 1})
// 使用 limit 对结果条数进行限制
db.s4.find().limit() // 不跟参数返回所有
db.s4.find().limit(3) // 返回匹配结果的前3条
db.s4.find().limit(1, 3) // 不支持的写法
复杂查询
运算符参考:https://www.cnblogs.com/Neeo/articles/14306535.html#operator
复杂查询主要掌握如何结合各种运算符过滤出符合条件的结果。
比较运算符
// t1 数据库下有集合 s4,现对该集合中的文档进行查询
// 等于
db.s4.find({"name": "zhangkai1"})
db.s4.find({"name":{$eq:"zhangkai1"}}) // 操作符支持 $eq 和 "$eq" 这两种写法,推荐带引号的写法
// 小于、小于等于
db.s4.find({"age":{$lt:18}})
db.s4.find({"age":{$lte:18}})
// 大于、大于等于
db.s4.find({"age":{$gt:18}})
db.s4.find({"age":{$gte:18}})
// 包含 where age in (18, 19)
db.s4.find({"age":{$in:[18, 19]}})
// 查询不等于指定值的文档
db.s4.find({"age":{$ne:18}})
逻辑运算符
// t1 数据库下有集合 s4,现对该集合中的文档进行查询
// and 下面两个语句等价
db.s4.find({"name": "zhangkai1", "age": 18})
db.s4.find({
$and:[
{"name": "zhangkai1"},
{"age": 18}
]
})
// or
db.s4.find({
$or:[
{"name": "zhangkai1"},
{"age": 18}
]
})
// not 注意,$not操作符不支持$regex正则表达式操作
db.s4.find({
"age":{
$not:{$lte:18}
}
})
db.s4.find({
"name":{
$not:{$eq:"zhangkai1"}
}
})
// where name != zhangkai1 and age = 19
db.s4.find({
$nor:[
{"name": "zhangkai1"},
{"age": 19}
]
})
元素查询运算符
// $exists:true 如果指定的key不存在,则返回该文档
// $exists:false 如果指定的key不存在,则返回该文档
db.s4.find({"mobile": {$exists: true}})
db.s4.find({"mobile": {$exists: false}})
// $type 如果指定key的值是指定类型,则返回该文档
db.s4.insert({"name": "likai", "age": 18, "money": 8.8, "hobby": ['guitar', 'read'], 'gender': true, "date": new Date()})
db.s4.find({"name":{$type:"string"}})
db.s4.find({"age":{$type:"integer"}})
db.s4.find({"money":{$type:"double"}})
db.s4.find({"hobby":{$type:"array"}})
db.s4.find({"gender":{$type:"bool"}})
db.s4.find({"date":{$type:"date"}})
// 以上列出常用的用于 $type 判断的类型,更多参考:https://docs.mongodb.com/manual/reference/operator/query/type/#available-types
评估查询运算符
$regex
为查询中的模式匹配字符串提供正则表达式功能 。MongoDB使用支持UTF-8的Perl兼容正则表达式(即“ PCRE”)版本8.42。
// 正则匹配
db.s4.insertMany([
{"name": "wangkai1", "age": 18, "mobile": "15011110000"},
{"name": "WANGKAI2", "age": 18, "mobile": "15011110000"},
{"name": "wangkai3", "age": 18, "mobile": "15111110000"},
])
db.s4.find({"mobile":{$regex:/^150/}})
db.s4.find({"name":{$regex:/^wang/}})
// 下面两条语句等价
db.s4.find({"name":{$regex:/^wang/i}})
db.s4.find({"name":{$regex:/^wang/, $options:"i"}})
$options
有以下几个选项可用于正则表达式:
选项 | 描述 | 语法限制 |
---|---|---|
i |
不区分大小写,以匹配大小写。有关示例,请参见执行不区分大小写的正则表达式匹配。 | |
m |
对于包含锚点的模式(即^ 开始, $ 结束),请在每行的开头或结尾匹配具有多行值的字符串。没有此选项,这些锚点将在字符串的开头或结尾匹配。有关示例,请参见以指定模式开头的行的多行匹配。如果模式不包含锚点,或者字符串值不包含换行符(例如\n ),则该m 选项无效。 |
|
x |
“扩展”功能可忽略模式中的所有空白字符,$regex 除非转义或包含在字符类中。此外,它会忽略介于两者之间的字符,包括未转义的井号/磅(# )字符和下一个新行,因此您可以在复杂模式中添加注释。这仅适用于数据字符;空格字符可能永远不会出现在图案的特殊字符序列中。该x 选项不影响VT字符(即代码11)的处理。 |
需要$regex 与$options 语法 |
s |
允许点字符(即. )匹配所有字符,包括换行符。有关示例,请参阅使用。点字符以匹配换行符。 |
需要$regex 与$options 语法 |
注意:该$regex
运营商不支持全局搜索修改g
。
更多细节参考:https://docs.mongodb.com/manual/reference/operator/query/regex/#op._S_regex
分组聚合
准备数据
db.s5.insertMany([
{'_id': 1, 'name': '陆莉', 'age': 36, 'department': '研发', 'city': '哈尔滨', 'salary': 34276},
{'_id': 2, 'name': '田玉', 'age': 23, 'department': '研发', 'city': '济南', 'salary': 44056},
{'_id': 3, 'name': '张荣', 'age': 55, 'department': '行政', 'city': '澳门', 'salary': 2243},
{'_id': 4, 'name': '张红梅', 'age': 43, 'department': '财务', 'city': '哈尔滨', 'salary': 39400},
{'_id': 5, 'name': '李娜', 'age': 53, 'department': '教学', 'city': '北镇', 'salary': 25965},
{'_id': 6, 'name': '杨建华', 'age': 28, 'department': '行政', 'city': '太原', 'salary': 37192},
{'_id': 7, 'name': '庞桂芳', 'age': 24, 'department': '财务', 'city': '柳州', 'salary': 25049},
{'_id': 8, 'name': '陈云', 'age': 56, 'department': '行政', 'city': '六盘水', 'salary': 4067},
{'_id': 9, 'name': '李玉英', 'age': 51, 'department': '教学', 'city': '广州', 'salary': 30600},
{'_id': 10, 'name': '杨慧', 'age': 23, 'department': '研发', 'city': '关岭', 'salary': 48794},
{'_id': 11, 'name': '孙琴', 'age': 46, 'department': '研发', 'city': '梧州', 'salary': 16250},
{'_id': 12, 'name': '张桂芳', 'age': 20, 'department': '财务', 'city': '呼和浩特', 'salary': 31412},
{'_id': 13, 'name': '丁秀梅', 'age': 28, 'department': '行政', 'city': '郑州', 'salary': 2439},
{'_id': 14, 'name': '万小红', 'age': 24, 'department': '行政', 'city': '西安', 'salary': 6153},
{'_id': 15, 'name': '钱建华', 'age': 47, 'department': '行政', 'city': '乌鲁木齐', 'salary': 3198},
{'_id': 16, 'name': '雷健', 'age': 56, 'department': '教学', 'city': '香港', 'salary': 3622},
{'_id': 17, 'name': '尤柳', 'age': 51, 'department': '财务', 'city': '哈尔滨', 'salary': 48016},
{'_id': 18, 'name': '刘莹', 'age': 46, 'department': '教学', 'city': '哈尔滨', 'salary': 18605},
{'_id': 19, 'name': '李秀梅', 'age': 35, 'department': '行政', 'city': '太原', 'salary': 5378},
{'_id': 20, 'name': '张淑英', 'age': 26, 'department': '财务', 'city': '大冶', 'salary': 36854},
{'_id': 21, 'name': '林红霞', 'age': 36, 'department': '财务', 'city': '拉萨', 'salary': 5292},
{'_id': 22, 'name': '周芳', 'age': 48, 'department': '财务', 'city': '荆门', 'salary': 3433},
{'_id': 23, 'name': '周芳', 'age': 30, 'department': '财务', 'city': '天津', 'salary': 4056},
{'_id': 24, 'name': '赵淑华', 'age': 50, 'department': '行政', 'city': '南宁', 'salary': 37898},
{'_id': 25, 'name': '何凤英', 'age': 45, 'department': '财务', 'city': '杭州', 'salary': 24429},
{'_id': 26, 'name': '司欣', 'age': 38, 'department': '教学', 'city': '长沙', 'salary': 49713},
{'_id': 27, 'name': '王亮', 'age': 27, 'department': '行政', 'city': '深圳', 'salary': 15875},
{'_id': 28, 'name': '颜柳', 'age': 51, 'department': '财务', 'city': '昆明', 'salary': 45560},
{'_id': 29, 'name': '卢柳', 'age': 39, 'department': '财务', 'city': '大冶', 'salary': 24864},
{'_id': 30, 'name': '刘秀芳', 'age': 52, 'department': '行政', 'city': '通辽', 'salary': 4741},
{'_id': 31, 'name': '王建军', 'age': 50, 'department': '财务', 'city': '齐齐哈尔', 'salary': 1625},
{'_id': 32, 'name': '霍红', 'age': 39, 'department': '财务', 'city': '北京', 'salary': 24373},
{'_id': 33, 'name': '葛倩', 'age': 44, 'department': '研发', 'city': '银川', 'salary': 8491},
{'_id': 34, 'name': '李秀梅', 'age': 27, 'department': '财务', 'city': '太原', 'salary': 26553},
{'_id': 35, 'name': '李红', 'age': 31, 'department': '教学', 'city': '呼和浩特', 'salary': 42143},
{'_id': 36, 'name': '宁凤英', 'age': 59, 'department': '行政', 'city': '南宁', 'salary': 18488},
{'_id': 37, 'name': '张秀珍', 'age': 53, 'department': '教学', 'city': '海口', 'salary': 19217},
{'_id': 38, 'name': '赵鑫', 'age': 23, 'department': '研发', 'city': '永安', 'salary': 13666},
{'_id': 39, 'name': '徐桂珍', 'age': 54, 'department': '行政', 'city': '澳门', 'salary': 8870},
{'_id': 40, 'name': '倪艳', 'age': 34, 'department': '教学', 'city': '澳门', 'salary': 47225},
{'_id': 41, 'name': '丁玉英', 'age': 48, 'department': '财务', 'city': '马鞍山', 'salary': 23588},
{'_id': 42, 'name': '何杰', 'age': 30, 'department': '财务', 'city': '呼和浩特', 'salary': 19936},
{'_id': 43, 'name': '班俊', 'age': 22, 'department': '行政', 'city': '巢湖', 'salary': 30159},
{'_id': 44, 'name': '邱红梅', 'age': 43, 'department': '研发', 'city': '惠州', 'salary': 34269},
{'_id': 45, 'name': '黄红梅', 'age': 51, 'department': '财务', 'city': '汕尾', 'salary': 46937},
{'_id': 46, 'name': '王凤英', 'age': 52, 'department': '财务', 'city': '重庆', 'salary': 23413},
{'_id': 47, 'name': '覃璐', 'age': 54, 'department': '财务', 'city': '六安', 'salary': 28359},
{'_id': 48, 'name': '黄瑜', 'age': 55, 'department': '教学', 'city': '海门', 'salary': 24756},
{'_id': 49, 'name': '孟丽娟', 'age': 39, 'department': '教学', 'city': '辛集', 'salary': 47526},
{'_id': 50, 'name': '王丽', 'age': 34, 'department': '财务', 'city': '海门', 'salary': 24091},
{'_id': 51, 'name': '王桂珍', 'age': 44, 'department': '教学', 'city': '杭州', 'salary': 23686},
{'_id': 52, 'name': '刘燕', 'age': 52, 'department': '行政', 'city': '西宁', 'salary': 22643},
{'_id': 53, 'name': '陈俊', 'age': 53, 'department': '教学', 'city': '银川', 'salary': 48200},
{'_id': 54, 'name': '廖丽丽', 'age': 35, 'department': '教学', 'city': '辛集', 'salary': 13419},
{'_id': 55, 'name': '董婷', 'age': 48, 'department': '财务', 'city': '西宁', 'salary': 20368},
{'_id': 56, 'name': '何桂荣', 'age': 24, 'department': '教学', 'city': '北京', 'salary': 25127},
{'_id': 57, 'name': '郭凯', 'age': 22, 'department': '研发', 'city': '辛集', 'salary': 8079},
{'_id': 58, 'name': '张博', 'age': 57, 'department': '行政', 'city': '张家港', 'salary': 25686},
{'_id': 59, 'name': '颜凯', 'age': 20, 'department': '研发', 'city': '乌鲁木齐', 'salary': 2194},
{'_id': 60, 'name': '李小红', 'age': 49, 'department': '财务', 'city': '福州', 'salary': 28882},
{'_id': 61, 'name': '吴倩', 'age': 52, 'department': '财务', 'city': '柳州', 'salary': 13382},
{'_id': 62, 'name': '祁玉珍', 'age': 36, 'department': '行政', 'city': '太原', 'salary': 28242},
{'_id': 63, 'name': '吴桂兰', 'age': 45, 'department': '行政', 'city': '济南', 'salary': 21206},
{'_id': 64, 'name': '曹建华', 'age': 50, 'department': '财务', 'city': '拉萨', 'salary': 25650},
{'_id': 65, 'name': '张雷', 'age': 41, 'department': '财务', 'city': '上海', 'salary': 11749},
{'_id': 66, 'name': '张淑兰', 'age': 29, 'department': '教学', 'city': '昆明', 'salary': 33699},
{'_id': 67, 'name': '徐琳', 'age': 36, 'department': '教学', 'city': '阜新', 'salary': 10631},
{'_id': 68, 'name': '黄红', 'age': 59, 'department': '研发', 'city': '东莞', 'salary': 26985},
{'_id': 69, 'name': '秦秀荣', 'age': 27, 'department': '财务', 'city': '乌鲁木齐', 'salary': 22490},
{'_id': 70, 'name': '何秀梅', 'age': 52, 'department': '财务', 'city': '昆明', 'salary': 6254},
{'_id': 71, 'name': '杨艳', 'age': 33, 'department': '研发', 'city': '海口', 'salary': 40186},
{'_id': 72, 'name': '汪桂英', 'age': 25, 'department': '研发', 'city': '嘉禾', 'salary': 6814},
{'_id': 73, 'name': '郭鹏', 'age': 37, 'department': '教学', 'city': '台北', 'salary': 20298},
{'_id': 74, 'name': '邓萍', 'age': 28, 'department': '教学', 'city': '潮州', 'salary': 27718},
{'_id': 75, 'name': '陈明', 'age': 50, 'department': '研发', 'city': '香港', 'salary': 41881},
{'_id': 76, 'name': '贺金凤', 'age': 43, 'department': '财务', 'city': '荆门', 'salary': 28221},
{'_id': 77, 'name': '梁旭', 'age': 32, 'department': '行政', 'city': '拉萨', 'salary': 9921},
{'_id': 78, 'name': '张阳', 'age': 55, 'department': '行政', 'city': '兴城', 'salary': 23353},
{'_id': 79, 'name': '吕坤', 'age': 54, 'department': '财务', 'city': '阜新', 'salary': 23551},
{'_id': 80, 'name': '胡飞', 'age': 20, 'department': '行政', 'city': '海门', 'salary': 19774},
{'_id': 81, 'name': '张俊', 'age': 24, 'department': '财务', 'city': '合山', 'salary': 14928},
{'_id': 82, 'name': '戴建', 'age': 33, 'department': '财务', 'city': '大冶', 'salary': 39383},
{'_id': 83, 'name': '刘娟', 'age': 40, 'department': '教学', 'city': '东莞', 'salary': 22757},
{'_id': 84, 'name': '盛丽娟', 'age': 28, 'department': '财务', 'city': '潮州', 'salary': 19360},
{'_id': 85, 'name': '马辉', 'age': 40, 'department': '研发', 'city': '广州', 'salary': 36599},
{'_id': 86, 'name': '刘秀兰', 'age': 33, 'department': '教学', 'city': '银川', 'salary': 27751},
{'_id': 87, 'name': '田莹', 'age': 52, 'department': '研发', 'city': '东莞', 'salary': 49509},
{'_id': 88, 'name': '林志强', 'age': 32, 'department': '行政', 'city': '石家庄', 'salary': 2703},
{'_id': 89, 'name': '曹红霞', 'age': 20, 'department': '研发', 'city': '乌鲁木齐', 'salary': 20836},
{'_id': 90, 'name': '熊莹', 'age': 22, 'department': '研发', 'city': '合肥', 'salary': 42514},
{'_id': 91, 'name': '侯超', 'age': 23, 'department': '行政', 'city': '荆门', 'salary': 32676},
{'_id': 92, 'name': '陈瑜', 'age': 42, 'department': '教学', 'city': '杭州', 'salary': 40729},
{'_id': 93, 'name': '李丽丽', 'age': 47, 'department': '财务', 'city': '成都', 'salary': 33203},
{'_id': 94, 'name': '朱淑华', 'age': 35, 'department': '财务', 'city': '北京', 'salary': 8754},
{'_id': 95, 'name': '王兰英', 'age': 26, 'department': '行政', 'city': '东莞', 'salary': 18682},
{'_id': 96, 'name': '石刚', 'age': 42, 'department': '教学', 'city': '上海', 'salary': 27357},
{'_id': 97, 'name': '高刚', 'age': 52, 'department': '研发', 'city': '太原', 'salary': 29452},
{'_id': 98, 'name': '李秀荣', 'age': 41, 'department': '财务', 'city': '长沙', 'salary': 48755},
{'_id': 99, 'name': '李志强', 'age': 56, 'department': '研发', 'city': '香港', 'salary': 15993},
{'_id': 100, 'name': '王平', 'age': 45, 'department': '行政', 'city': '马鞍山', 'salary': 15113}
])
接下来演示聚合分组常见的用法。
\(match和\)group
$match
和$group
相当于SQL中的where
和group by
,在聚合后还可以搭配使用$min
、$max
、$avg
、$sum
这些聚合函数,也可以搭配使用排序使用,基本语法参考:
db.collection.aggregate([
{$match: {"字段": "条件"}}, // 可以跟常用的查询操作符,如 $gt $lt $in
{$group: {"_id": "分组字段", "新的字段": "聚合操作符"}}
])
聚合函数的应用
// t1 数据库下有集合 s5,现对该集合中的文档进行查询
// 查询 department="财务" 的文档 where department = "财务"
db.s5.aggregate([
{"$match": {"department": "财务"}}
])
// 查询 id > 10 的文档,且以 department 分组 where id > 3 group by department
db.s5.aggregate([
{"$match": {"_id": {"$gt": 10}}},
{"$group": {"_id": "$department"}}
])
// 查询 id > 10 的文档,且以 department 分组,并查看每个部门的平均薪水
db.s5.aggregate([
{"$match": {"_id": {"$gt": 10}}},
{"$group": {
"_id": "$department", // 第一个参数必须是 _id
"avg_salary": {"$avg": "$salary"},
// "min_age": {"$min": "$age"} // 可以跟多个聚合条件
}
}
])
// 查询 id > 10 的文档,且以 department 分组,并查看每个部门的平均薪水,然后过滤平均薪水大于 25000 的
db.s5.aggregate([
{"$match": {"_id": {"$gt": 10}}},
{"$group": {
"_id": "$department", // 第一个参数必须是 _id
"avg_salary": {"$avg": "$salary"},
// "min_age": {"$min": "$age"} // 可以跟多个聚合条件
}
},
{"$match": {"avg_salary": {"$gt": 25000}}} // 直接引用上条结果中的 avg_salary
])
// 以 department 分组,并求出每个分组的最高薪水、最低薪水、最大年龄和最小年龄
db.s5.aggregate([
{"$group": { // 注意,分组内的结果不一定是有序的,但最大最小操作符都能处理
"_id": "$department",
"max_salary": {"$max": "$salary"},
"min_salary": {"$min": "$salary"},
"max_age": {"$max": "$age"},
"min_age": {"$min": "$age"},
}}
])
排序的使用
// 如果是分组聚合的结果是有序的,请用 $first 和 $last 代替 $max 和 $min,因为 $first 和 $last 效率更高
// 按 department 分组,并且求最大和最小薪水
db.s5.aggregate([
{"$sort": {"salary": 1}}, // 首先要排序, 1 表示升序
{"$group": {
"_id": "$department",
"max_salary": {"$max": "$salary"},
"min_salary": {"$min": "$salary"},
"last_salary": {"$last": "$salary"}, // 最后一个,相当于取有序集合的最后一个
"first_salary": {"$first": "$salary"}, // // 第一个,相当于取有序集合的第一个
}}
])
// $sum 求每个部门的总薪水,并根据每个部门的总薪水进行升序排序
db.s5.aggregate([
// 先分组
{"$group": {
"_id": "$department",
"count_salary": {
"$sum": "$salary"
}
}},
// 根据分组结果进行排序
{"$sort": {
"count_salary": 1
}}
])
// $sum 求每个部门的人数,并根据每个部门的总人数进行降序排序
db.s5.aggregate([
{"$group": {
"_id": "$department",
"count_pepole": {
"$sum": 1 // 不用跟具体的条件,每出现一条记录就加一
}
}},
{"$sort": {
"count_pepole": -1
}}
])
数组操作符
数组操作符这里,掌握两个操作符:
$push
:如果文档有重复,将其中一个也添加到数组中。$addToSet
:只将不重复的文档添加到数组中。
// 查询各部门及各部门的人员姓名
db.s5.aggregate([
{"$group": {
"_id": "$department",
"name_list": {
"$push": "$name"
}
}}
])
$project
// 通过为指定键设置 1/0 来决定是否显式
db.s5.aggregate([
{
"$project": {
"_id": 0, // _id字段是默认显式的,可以通过 0 设置取消显式
"name": 1,
"age": 1,
"new_age": {
"$add": ["$age", 1] // 所有 age 自加一
}
}
}
])
$limit、$skip和$sample
$limit
用于过滤结果条数。
$skip
用于跳过多少篇文档。
$sample
表示随机选取几篇文档。
// 获取平均工资最高的前三个部门
db.s5.aggregate([
{"$group": {
"_id": "$department",
"avg_salary": {"$avg": "$salary"}
}},
{"$sort": {
"avg_salary": -1
}},
{"$limit": 3}
])
// 取平均工资最高的前三个部门中的第二个部门
db.s5.aggregate([
{"$group": {
"_id": "$department",
"avg_salary": {"$avg": "$salary"}
}},
{"$sort": {
"avg_salary": -1
}},
{"$limit": 2}, // 返回前两条数据
{"$skip": 1} // 跳过第一条
])
// 随机返回5篇文档
db.s5.aggregate([
{"$sample": {
"size": 5
}}
])
$concat、$substr、$toLower、$toUpper
$concat
将指定的表达式或者字符串拼接后返回。
$substr
截取非中文字符串。
$toLower
字符串转小写。
$toUpper
字符串转大写。
// 添加一条数据
db.s6.insert({"name": "Anthony"})
// 拼接字符串
db.s6.aggregate([
{"$project": {
"_id": 0,
"name": {
"$concat": ["$name", "$name", "$name"] // 将数组内的每个元素都进行拼接
}
}}
])
// 截取
db.s6.aggregate([
{"$project": {
"_id": 0,
"name": {
"$substr": ["$name", 0, 2] // 返回索引为 0, 1 的字符
}
}}
])
// 转大写/转小写
db.s6.aggregate([
{"$project": {
"_id": 0,
"toUpper": {
"$toUpper": "$name" // 将 name 值的小写字母转da写
},
"toLower": {
"$toLower": "$name" // 将 name 值的大写字母转小写
}
}}
])
更新文档
更新文档使用以下两个方法:
// 更新一条
db.collection.update(
<query>, // update的查询条件,一般写法:{"属性":{条件:值}}
<update>, // update的更新数据,一般写法 { $set:{"属性":"值"} } 或者 { $inc:{"属性":"值"} }
{
upsert: <boolean>, // 可选参数,如果文档不存在,是否插入, true为插入,默认是false,不插入
multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新
writeConcern: <document> // 可选参数,抛出异常的级别。
}
)
// 更新多条
db.collection.updateMany(
<query>, // update的查询条件,一般写法:{"属性":{条件:值}}
<update>, // update的对象,一般写法 { $set:{"属性":"值"} } 或者 { $inc:{"属性":"值"} }
{
upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入
multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新
writeConcern: <document> // 可选参数,抛出异常的级别。
}
)
更新操作通常可以结合更新相关的运算符结合使用:
// t1 数据库下有集合 s4,现对该集合中的文档进行更新操作
// 更新一篇文档的指定字段,将 _id = ObjectId("600a32c1a20e39fe696c73d1") 的文档的 age 更新为20
db.s4.update(
{"_id": ObjectId("600a32c1a20e39fe696c73d1")},
{$set:
// 只更新文档中的 age 字段,不影响其他字段,如果字段不存在就添加
{"age": 22, "name": "wangkai2"},
// {"age": 22, "name": "wangkai2"} // 更新多个字段值
}
)
// 覆盖更新,只保留更新后的字段
db.s4.update(
{"_id": ObjectId("600a32c1a20e39fe696c73d1")},
// 这么写,相当于覆盖更新文档,即更新后的文档,只保留 age 和 _id 字段(_id字段也是MongoDB自动生成的)
{"age": 20}
)
// 更新多篇文档中的指定字段
db.s4.updateMany(
{"name": {$regex: /^zhangkai/i}}, // where name like "zhangkai%"
{$set:
{"gender": "男"} // 如果字段不存在则添加,存在则修改
}
)
// 自增/自减,可以指定任意正负整数值
db.s4.update(
{"_id": ObjectId("600a32c1a20e39fe696c73d1")},
{$inc:
{"age": 1} // age 自增 1
// {"age": -1} // age 自减 1
// {"age": 3} // age 自增 3
// {"age": -3} // age 自减 3
}
)
// 指定字段重命名
db.s4.updateMany(
{"name": {$regex: /^wangkai/i}}, // 匹配以 wangkai 开头的 name
{$rename:
{"mobile": "tel"} // 将 mobile 字段重命名为 tel
}
)
// 添加一个字段
db.s4.updateMany(
{"tel": {$exists:false}}, // 匹配 tel 字段不存在的文档
{$set:
{"tel": "15011101112"} // 添加 tel 字段
}
)
// 删除指定字段
db.s4.updateMany(
{"tel": {$regex: /^150/}}, // 匹配以 150 开头的 tel
{$unset:
{"tel": ""} // 将 tel 字段删除
}
)
还有关于array的操作:
// 准备些数据
db.s4.insertMany([
{"name": "sunkai1", "age": 18, "friends": ["anthony", "maggie", "tom", "neeo"]},
{"name": "sunkai2", "age": 18, "friends": ["jack", "maggie", "ben"]},
])
// 为数组添加一个成员
db.s4.update(
{"name": "sunkai2"},
{$push:
{"friends": "mary"}
}
)
// 为数组移除指定成员
db.s4.update(
{"name": "sunkai2"},
{$pull:
{"friends": "mary"}
}
)
// 移除数组索引为 0 或者 -1 的成员
db.s4.update(
{"name": "sunkai1"},
{$pop:
{"friends": 1}, // 1 移除索引为 -1 的成员
// {"friends": -1} // -1 移除索引为 0 的成员
}
)
更多的更新操作运算符,参考:https://www.cnblogs.com/Neeo/articles/14306535.html
删除文档
删除使用remove
方法:
db.collection.remove(
<query>, // remove的查询条件,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档
{
justOne: <boolean>, // 可选删除,是否只删除查询到的第一个文档,默认为false,删除所有
writeConcern: <document> // 可选参数,抛出异常的级别。
}
)
一般用法:
// 删除指定文档,通过query条件和justOone来控制删除的数量
db.s4.remove(
{"_id": ObjectId("600a32c1a20e39fe696c73d1")}, // 精确匹配到一篇文档
{"justOne": true} // justOne:true 删除一个, 如果只匹配一篇文档,可以不写这个参数
)
// 删除多篇文档
db.s4.remove(
{"name": {$regex:/^zhangkai/i}}, // 匹配结果可能有多个
// {"justOne": true}, // justOne:true 删除一个
{"justOne": false} // 将匹配到的文档全部删除
)
// 清空集合中的文档
db.s4.remove({})
that's all, see also: