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中的wheregroup 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:

老男孩-标杆班级-NoSQL-lesson14-MongoDB核心技术-运维篇

posted @ 2021-01-14 10:22  听雨危楼  阅读(331)  评论(0编辑  收藏  举报