MongoDB学习笔记,基础+增删改查+索引+聚合

基础了解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
对应关系 -> https://docs.mongodb.com/manual/reference/sql-comparison/
database -> database
collection -> table
document -> row //无模式
field -> column
--------------------------------------------------------------------------------------
使用数据库
use 数据库名称

创建数据库并创建集合myNewCollection1插入数据
use myNewDB
db.myNewCollection1.insertOne( { x: 1 } )
--------------------------------------------------------------------------------------
创建集合并插入数据
db.myNewCollection22.insertOne( { xxx: 1 } )

固定大小集合 capped collection 先进先出
创建一个集合x1 是上限集合,大小200字节 最大2个document,先进先出
也可以不指定document大小db.createCollection("x1", { capped : true, size : 200} )
db.createCollection("x1", { capped : true, size : 200, max : 2 } )

检查是否为上限集合 false true
db.collection.isCapped()

返回集合有多少document
db.collection.count()

转换为上限集合
db.runCommand({"convertToCapped": "collection", size: 100000});

查看collection并升序转换成数组输出,降序 -1
printjson(db.collection.find().sort({$natural:1}).toArray())

collection methods ->
https://docs.mongodb.com/manual/reference/method/js-collection/
--------------------------------------------------------------------------------------
BSON Types

插入数据为undefined
db.collection.insert({x:undefined})
查找需要
db.getCollection('a001').find({x:undefined})//错误
db.getCollection('a001').find({x:{$type:6}})
db.getCollection('a001').find({x:{$type:"undefined"}})

详情:$type对应Number https://docs.mongodb.com/manual/reference/bson-types/

_id 5d89674154e8289fdac72ea5 十六进制

八位 5d896741 表示时间 十进制 1569285953 北京时间 2019/9/24 8:45:53
十位 54e8289fda 随机数 十进制 364672229338
六位 c72ea5 计数器从随机数开始 十进制 13053605

16 -> 10 进制 https://tool.lu/hexconvert/
时间戳 -> 北京时间 https://tool.chinaz.com/Tools/unixtime.aspx

基本查询操作

写在一起中间无换行表示同一个效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// db.people.insertOne( {//插入并创建表
// user_id: "abc123",
// age: 55,
// status: "A"
// } )

// db.people.createIndex( { user_id: 1 } )//创建 增索引

// db.people.createIndex( { user_id: 1, age: -1 } )//创建 增索引 和 减索引

// db.people.drop()//删除表

// db.people.updateMany(//设置列 join_date 内容为当前时间,列没有就添加
// { },
// { $set: { join_date: new Date() } }
// )

// db.people.updateMany(//删除所有列 join_date
// { },
// { $unset: { "join_date": "" } }
// )

// db.people.insertOne(//插入一条数据
// { user_id: "bcd001", age: 45, status: "A" }
// )

// db.people.find()//查询所有数据

// db.people.find(//只查询三个字段 _id user_id status
// { },
// { user_id: 1, status: 1 }
// )

// db.people.find(//只查询两个字段 user_id status
// { },
// { user_id: 1, status: 1, _id: 0 }
// )

// db.people.find(//查询状态不等于A
// { status: { $ne: "A" } }
// )

// db.people.find(//查询status="A" AND age=50
// { status: "A",
// age: 50 }
// )

// db.people.find(//查询status="A" OR age=50
// { $or: [ { status: "A" } , { age: 50 } ] }
// )

// db.people.find(// >25
// { age: { $gt: 25 } }
// )

// db.people.find(// <25
// { age: { $lt: 25 } }
// )

// db.people.find(// >25 <=50
// { age: { $gt: 25, $lte: 50 } }
// )

// db.people.find( { user_id: /abc/ } )// LIKE '%abc%'
// db.people.find( { user_id: { $regex: /abc/ } } )

// db.people.find( { user_id: /^abc/ } )// LIKE 'abc%'
// db.people.find( { user_id: { $regex: /^abc/ } } )

// db.people.find( { status: "A" } ).sort( { user_id: 1 } )//ASC

// db.people.find( { status: "A" } ).sort( { user_id: -1 } )//DESC

// db.people.count()// count(*)
// db.people.find().count()

// db.people.count( { user_id: { $exists: true } } )// 含有user_id的所有count(*)
// db.people.find( { user_id: { $exists: true } } ).count()

// db.people.count( { age: { $gt: 500 } } )//age>500的count(*)
// db.people.find( { age: { $gt: 500 } } ).count()

// db.people.aggregate( [ { $group : { _id : "$status" } } ] )//安装status分组,查询别名_id 只查询status
// db.people.distinct( "status" )//返回一个数组 ["A","B","C","CCCC"]

// db.people.findOne()//查询第一条
// db.people.find().limit(1)

// db.people.find().limit(5).skip(10)//查询大于第 11 12 13 14 15条,如果没有14 15 就显示 11 12 13

// db.people.updateMany(//更新年龄大于5555的状态设置为CCCC
// { age: { $gt: 5555 } },
// { $set: { status: "CCCC" } }
// )

// db.people.updateMany(//更新状态为CCCC的设置
// { status: "CCCC" } ,
// { $inc: { age: 3 } }
// )

// db.people.deleteMany( { status: "D" } )//删除状态为D的所有数据

// db.people.deleteMany({})//清空表数据

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
查询

比较查询操作符 -> https://docs.mongodb.com/manual/reference/operator/query-comparison/

$eq -> = -> { <field>: { $eq: <value> } }

$ne -> != -> {field: {$ne: value} }

$gt -> > -> { field: { $gt: value} }

$gte -> >= -> { field: { $gte: value} }

$lt -> < -> { field: { $lt: value} }

$lte -> <= -> { field: { $lte: value} }

有一个就可以
$in -> in -> { field: { $in: [<value1>, <value2>, ... <valueN> ] } }

都没有才可以
$nin -> not in -> { field: { $nin: [ <value1>, <value2> ... <valueN> ]} }
--------------------------------------------------------------------------------------
逻辑查询操作符 -> https://docs.mongodb.com/manual/reference/operator/query-logical/

第一个false 余下不执行
$and -> and -> { $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] }

$or -> or -> { $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }

对or的结果取反
$nor -> not or -> { $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }

对符合的结果取反
$not -> not -> { field: { $not: { <operator-expression> } } }
--------------------------------------------------------------------------------------
元素查询操作符 -> https://docs.mongodb.com/manual/reference/operator/query-element/

$exists -> exists -> { field: { $exists: true/false } }

$type -> { field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
// { field: { $type: "string" } }
// { field: { $type: ["string","int"] } }
--------------------------------------------------------------------------------------
评估查询操作符 -> https://docs.mongodb.com/manual/reference/operator/query-evaluation/

// 根据表达式来匹配数据
$expr -> { $expr: { <expression> } }

// 根据schema来匹配 required必须含有,properties属性,bsonType类型
$jsonSchema -> { $jsonSchema: <JSON Schema object> }

这里匹配 如果field=0,1,2,3,4,5 v1=2 v2=1 表示除2余1的数,所以是1 3 5
$mod -> { field: { $mod: [ v1, v2 ] } }

匹配正则表达式
{filed:{$regex:/a/}} -> 只要含有a,区分大小写
{filed:{$regex:/^a/}} -> 第一个字母是a,区分大小写
$regex -> 通常用 方式3
{ <field>: { $regex: /pattern/, $options: '<options>' } }//方式1
{ <field>: { $regex: 'pattern', $options: '<options>' } }//方式2
{ <field>: { $regex: /pattern/<options> } }//方式3

全文检索,不支持中文,根据索引进行匹配,
$text -> 例如 { $text: { $search: "coffee" } } 查找含有coffee的

非常强大 支持js
$where
例如
db.x.find({
$where:function(){
return this.item=="ijk123"&&this.qty==3 //this表示document(行)
}
})
--------------------------------------------------------------------------------------
数组查询操作符 -> https://docs.mongodb.com/manual/reference/operator/query-array/

必须所有的值都要有,$in则表示只有一个就可以
$all -> { <field>: { $all: [ <value1> , <value2> ... ] } }

只要匹配一个满足就可以
$elemMatch -> { <field>: { $elemMatch: { <query1>, <query2>, ... } } }
例如:
{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }
{ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } }

根据数组大小匹配
$size ->
匹配数组大小为2的,两个效果相同
{ field: { $size: 2 } }
{$where:function(){return this.field.length==2}}

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
更新

db.collection.update({},{$set:{"a":1}})更新第一条
db.collection.updateMany({},{$set:{"a":1}})更新全部

自动更新操作符 -> https://docs.mongodb.com/manual/reference/operator/update-field/
$inc -> { $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }
{},{$inc:{"age":1,"c":-2,"h.g":2}}//age+1 c-2 h.g+2 字段不存在会创建0+数值

$mul -> { $mul: { <field1>: <number1>, ... } }
{},{$mul:{"age":5,"h":-1}}//age*5 h*(-1) 数值也可为小数,字段不存在会创建为0*数值

新值最小 就更新
$min -> { $min: { <field1>: <value1>, ... } }

新值最大 就更新
$max -> { $max: { <field1>: <value1>, ... } }

$rename -> {$rename: { <field1>: <newName1>, <field2>: <newName2>, ... } }
{},{$rename:{"age":"age1","my.doc":"c.h"}}//更新字段 age -> age1 my.doc -> c.h

$set -> { $set: { <field1>: <value1>, ... } }
//如果不存在_id:1 不会做任何反应,如果存在,则会字段重新赋值,不存在的字段会添加
{_id:1},{$set:{"a":1,"h.g":2}}

$unset -> { $unset: { <field1>: "", ... } }
{},{$unset:{"a":""}}//字段a后面设置"" 这里就删除了字段a,不论a是什么类型

$setOnInsert ->
db.collection.update(
<query>,
{ $setOnInsert: { <field1>: <value1>, ... } },
{ upsert: true }
)

例如:
db.collection.update(//collection为空 会插入一个文档,并且设置一条 _id:1 c1:apple c2:100
{ _id: 1 },
{
$set: { c1: "apple" },
$setOnInsert: { c2: 100 }
},
{ upsert: true }
)

$currentDate -> { $currentDate: { <field1>: <typeSpecification1>, ... } }
也可以把 date 换成 timestamp 字符戳
{},{$currentDate:{mydate:{$type:"date"}}}

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
数组

$ -> { "<array>.$" : value }
可以作为占位符 表示一个 //_id=1 grades=80的把 grade.$ 改为999 只能改一条,改第一个
{ _id: 1, grades: 80 },
{ $set: { "grades.$" : 999 } }
{ "_id" : 1, "grades" : [ 85, 80, 80 ] } -> { "_id" : 1, "grades" : [ 85, 999, 80 ] }

$[] -> { <update operator>: { "<array>.$[]" : value } }
可以做占位符 表示全部
{_id:1},{$inc:{"sz.$[]":3}}
{_id:1,sz:[1,2,3]} -> {_id:1,sz:[4,5,6]}

$[diy] -> 这里的diy可以随便改 就是一个标识符
{},{$set:{"sz.$[x]":777}},{arrayFilters:[{"$[x]":{$eq:3}}]}
{"_id:1","sz":[3,5,3]}
{"_id:2","sz":[3,3,8]}

{"_id:1","sz":[777,5,777]},
{"_id:2","sz":[777,777,8]}

$addToSet -> { $addToSet: { <field1>: <value1>, ... } }
将元素添加数组
{_id:1},{$addToSet:{"sz":"3"}} ->{"sz":["1","2"]} ->{"sz":["1","2","3"]}
{_id:1},{$addToSet:{"sz":["4","5"]}} ->{"sz":["1","2"]} ->{"sz":["1","2",["4","5"]]}

$pop -> { $pop: { <field>: <-1 | 1>, ... } }
{_id:1},{$pop:{"sz":-1}}//移除数组第一个
{_id:1},{$pop:{"sz":1}}//移除数组最后一个

$pull -> { $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
字段后面跟条件
{ _id: 1 }, { $pull: { scores: {$in:[0,5]} } }//自定义删除所有 0和5
{ _id: 1 }, { $pull: { scores: {$gt:7} } }//删除大于7的

$pullAll -> { $pullAll: { <field1>: [ <value1>, <value2> ... ], ... } }
删除数组所有的 0 和 5
{ _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } }

$push -> { $push: { <field1>: <value1>, ... } }
{_id:1},{$push:{"sz":3}} -> {"sz":[1,2]} -> {"sz":[1,2,3]}//单个添加
{_id:1},{$push:{"sz":[4,5]}} -> {"sz":[1,2]} -> {"sz":[1,2,[4,5]]}//整体添加单个数组
{_id:1},{$push:{"sz":{$each:[4,5]}}} -> [1,2] -> [1,2,4,5]//批量添加
{_id:1},{$push:{"sz":{$each:[],$sort:1}}} -> [2,1,3] -> [1,2,3]//数组排序 1升序 -1降序
{_id:1},{$push:{"sz":{$each:[8,2],$sort:1}}} -> [2,1,3] -> [1,2,,2,3,8]//添加+排序
{_id:1},{$push:{"sz":{$each:[5,6],$sort:1,$slice:3}}}
原数据 -> 添加 -> 排序(1升序 -1降序) -> 截取(3前三条 -3后三条)
[2,1,3] -> [2,1,3,5,6] ->[1,2,3,5,6] ->[1,2,3]

$each
{ $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }
{ $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }

{_id:1},{$addToSet:{"sz":{$each:[4,5]}}}// [2,1] -> [2,1,4,5]
{_id:1},{$push:{"sz":{$each:[4,5]}}}// [2,1] -> [2,1,4,5]

$slice 截取 -> 配合$push $each一起使用
{_id:1},{$push:{"sz":{$each:[8,6],$slice:3}}}
[1,2] -> [1,2,8]// 3前三条 -3后三条 0清空数组

$sort 排序 -> 配合$push $each一起使用
{_id:1},{$push:{"sz":{$each:[8,6],$sort:1}}}
[1,2] -> [1,2,6,8]// 1升序 -1降序

$position 插入位置 -> 配合$push $each一起使用
{_id:1},{$push:{"sz":{$each:[9],$position:1}}}
[3,5,8] -> [3,1,5,8]
1表示在第一个元素后面追加 0表示在开头添加 大于元素个数表示在最后追加

增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
增删改查

insert
db.collection.insertOne({})//插入一条
db.collection.insertOne({})//插入第一条
db.collection.insertMany([{},{}])//插入多条
db.collection.insert({})//插入一条
db.collection.insert({},{})//插入第一条
db.collection.insert([{},{}])//插入多条

delete
db.collection.deleteOne({"a":1})//删除a为1的第一条
db.collection.deleteMany({"a":1})//删除a为1的全部
db.collection.deleteMany({})//清空collection
db.collection.remove()
{"a":1}//删除a为1的全部
{"a":1},{justOne:true}//删除a为1的第一条

update
db.collection.updateOne({"a":1},{$set:{"a":2}})//更新第一条
db.collection.updateOne({"a":1},{$set:{"a":2}})//更新全部
db.collection.replaceOne({"a":1},{"b":2,"c":3})//替换第一条的数据

find
db.collection.findOne({"a":1})//查询符合条件的第一条数据
db.collection.find({})//查询collection全部数据
db.collection.findOneAndDelete({"a":1})//查询正常返回第一条并且删除
db.collection.findOneAndReplace({"a":1},{"c":2,"d":3})//查询正常返回第一条并且替换
//查询正常返回第一条并更新,字段不存在就添加
db.collection.findOneAndUpdate({"d":"dd"},{$set:{"e":"ee"}})

bulk 支持以下方法,一个出错,不影响其他的
insertOne
updateOne
updateMany
replaceOne
deleteOne
deleteMany

try {
db.characters.bulkWrite(
[
{ insertOne :
{
"document" :
{
"_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
}
}
},
{ insertOne :
{
"document" :
{
"_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3
}
}
},
{ updateOne :
{
"filter" : { "char" : "Eldon" },
"update" : { $set : { "status" : "Critical Injury" } }
}
},
{ deleteOne :
{ "filter" : { "char" : "Brisbane"} }
},
{ replaceOne :
{
"filter" : { "char" : "Meldane" },
"replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
}
}
]
);
}
catch (e) {
print(e);
}

索引创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
索引创建

Single Index 单键索引
db.collection.createIndex({"a":1})//a非数组 1升序索引 -1降序索引

Compound Index 复合索引
db.collection.createIndex( { "a": 1, "b": 1 } )

Multikey Index 多键值索引
db.collection.createIndex({"a":1})//这里的a是一个数组
db.collection.createIndex({"a":1,"b":1})//a数组 b非数组 创建复合索引

Text Indexes 全文索引,不支持中文
db.collection.createIndex( { "a": "text" } )

Hashed Indexes 哈希索引
db.collection.createIndex( { "_id": "hashed" } )

Unique Indexes 唯一索引
插入数据不可以重复
db.collection.createIndex( { "a": 1 }, { unique: true } )

Partial Indexes 局部索引
db.users.createIndex(//年龄>=21才能给username加升序索引,唯一索引
{ username: 1 },
{ unique: true, partialFilterExpression: { age: { $gte: 21 } } }
)

Sparse Indexes 稀疏索引
db.collection.createIndex({"a":1},{sparse:true})//对a建立索引

TTL Indexes 过期索引*重要,可做定时过期
1,只支持单个索引,复合索引不支持
2,类型要为 BSON 日期 或 含有 BSON 日期的数组
3,expireAfterSeconds 单位秒,正的 或 0 ,如果为0 在指定日期时到期
4,如果是数组,最小的那个时间到期就会删除
5,不含有该索引字段 或 字段不是日期类型,不会过期
6,_id 不能设置 TTL索引
7,时间到期后不会立马删除,后台60s执行一次

只能设置一个字段,单位秒
db.collection.createIndex({"a":1},{expireAfterSeconds:65})

索引管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
索引管理

//插入自定义时间
db.test.insert({'time':ISODate("2012-11-02 07:58:51")})

查看
表的全部索引
db.collection.getIndexes()

索引字段名
db.collection.getIndexKeys()

数据库全部索引
db.getCollectionNames().forEach(function(collection) {
indexes = db[collection].getIndexes();
print("Indexes for " + collection + ":");
printjson(indexes);
});

删除
删除b升序索引 -1删除降序索引
db.collection.dropIndex({"b":1})

删除全部索引
db.collection.dropIndexes()

修改
删除再创建

GridFS 分布式文件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
GridFS 分布式文件系统

1,多机器储存备份
2,可以突破一般文件的限制,可以大于16M
3,分段存储,不是整个存储

mongofiles -> https://docs.mongodb.com/manual/reference/program/mongofiles/

默认localhost:27017
--host

默认27017
--port

指定数据库
--db

前缀 默认fs
--prefix
....
...
...

聚合管道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
聚合管道 Aggregation Pipeline Stages -> https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

db.collection.aggregate([{},{},...,{}])//一个{}表示一个管道
1,$addFields
2,$bucket
3,$bucketAuto
4,$collStats
5,$count

aggregate([//查询字段score>80的总数,假设有3条记录 返回{"passing_scores":3}
{
$match: {
score: {$gt: 80}
}
},
{
$count: "passing_scores"
}
]);

6,$facet
7,$geoNear
8,$graphLookup
9,$group

{
$group:
{
_id: null或者$字段
<field1>: { <accumulator1> : <expression1> },
...
}
}

$sum 相加
对字段price*quantity的结果相加得到总价格
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }
$avg 平均值
邱quantity字段平均值
averageQuantity: { $avg: "$quantity" }
$first 第一个值
$last 最后一个值
$min 最小值
$max 最大值
$push 对结果
对author分组,每个作者的标题String放入books数组
{ $group : { _id : "$author", books: { $push: "$title" } } }

aggregate( [//不分组 计算document数量
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
] );

{ "_id" : null, "count" : 8 }
---
aggregate( [ { $group : { _id : "$item" } } ] );//按照item字段分组

{ "_id" : "abc" }
{ "_id" : "jkl" }
{ "_id" : "def" }
{ "_id" : "xyz" }
---
aggregate(
[
// First Stage
{
$group :
{
_id : "$item",
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }
}
},
// Second Stage
{
$match: { "totalSaleAmount": { $gte: 100 } }
}
]
)
//先按照item分组,对字段price*quantity的结果相加得到总价格,如果总价格>=100就显示
---
$group : {
_id : null,
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
计算所有行的总销售额,所有行的quantity平均值,所有行的数量

10,$indexStats
11,$limit

aggregate(//取5条数据
{ $limit : 5 }
);

12,$listSessions
13,$lookup 表关联

aggregate([
{
$lookup:
{
from: "表2",
localField: "表1字段",
foreignField: "表2字段",
as: "表1添加列名,类型数组,放匹配表2的document"
}
},
{$match:{"_id":1}}//对结果再进行匹配 _id:1
]);
// localField String -> foreignField String
// localField String[] -> foreignField String

14,$match -> { $match: { <query> } }

aggregate(
[ { $match : { author : "dave" } } ]
);

15,$merge
16,$out

aggregate([//把匹配到的结果放入diy的表中,如果已存在则自动清空内容再插入
{
$match: {score: {$gt: 80}}
},
{
$out: "diy"
}
]);

17,$planCacheStats
18,$project -> 要显示哪些字段

只显示_id title author字段
aggregate( [ { $project : { title : 1 , author : 1 } } ] )

只显示title author字段
aggregate( [ { $project : { _id: 0, title : 1 , author : 1 } } ] )

不显示lastModified字段
aggregate( [ { $project : { "lastModified": 0 } } ] )

不显示author.first lastModified字段
aggregate( [ { $project : { "author.first" : 0, "lastModified" : 0 } } ] )

不显示author字段中的first lastModified字段
aggregate( [ { $project: { "author": { "first": 0}, "lastModified" : 0 } } ] )

显示title author.first author.last
并显示字段 author.middle,值不能为"" 或 不存在字段
aggregate( [
{
$project: {
title: 1,
"author.first": 1,
"author.last" : 1,
"author.middle": {
$cond: {
if: { $eq: [ "", "$author.middle" ] },
then: "$$REMOVE",
else: "$author.middle"
}
}
}
}
] );

aggregate( [ { $project: { "stop.title": 1 } } ] )
等同于
aggregate( [ { $project: { stop: { title: 1 } } } ] )

aggregate(
[
{
$project: {
title: 1,
isbn: {
prefix: { $substr: [ "$isbn", 0, 3 ] },//下标 0 1 2
group: { $substr: [ "$isbn", 3, 2 ] },//下标 3 4
publisher: { $substr: [ "$isbn", 5, 4 ] },//下标 5 6 7 8
title: { $substr: [ "$isbn", 9, 3 ] },//下标 9 10 11
checkDigit: { $substr: [ "$isbn", 12, 1] }//下标 12
},
lastName: "$author.last",//添加新字段
copiesSold: "$copies"//添加新字段
}
}
]
)

数组 例子 { "_id" : 1, "x" : 1, "y" : 1 }
aggregate( [ { $project: { myArray: [ "$x", "$y" ] } } ] )
->{ "_id" : 1, "myArray" : [ 1, 1 ] }

原字段中无someField,显示null
aggregate( [ { $project: { myArray: [ "$x", "$y", "$someField" ] } } ] )
-> { "_id" : 1, "myArray" : [ 1, 1, null ] }

19,$redact
20,$replaceRoot
21,$replaceWith
22,$sample
23,$set
24,$skip -> { $skip: <positive integer> }

aggregate(// 不显示前面5条记录
{ $skip : 5 }
);

25,$sort ->{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

aggregate([// 1升序 -1降序
{ $sort : { age : 1, posts: -1 } }
])

26,$sortByCount
27,$unset
28,$unwind

mapReduce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
mapReduce 重量级聚合 -> mapReduce -> map -> reduce -> finalize -> out


流程图解 -> https://docs.mongodb.com/manual/core/map-reduce/
使用方法 -> https://docs.mongodb.com/manual/reference/command/mapReduce/
db.runCommand({
mapReduce: <collection>,
map: <function>,
reduce: <function>,
finalize: <function>,
out: <output>,
query: <document>,
sort: <document>,
limit: <number>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>,
collation: <document>,
writeConcern: <document>
});

方法介绍 -> https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/

db.collection.mapReduce(
<map>,
<reduce>,
{
out: <collection>,
query: <document>,
sort: <document>,
limit: <number>,
finalize: <function>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>
}
)

常用四项:
1,map
function(){
emit(this.cust_id, this.price);
}
发射出去 key-value , 这里 this就是当前的document
2,reduce
function(key, values) {
return result;//result类型与map类型一致
}
3,query
{ age:{ $gte: 18 }}
4,finalize
在reduce后执行
function(key, reducedValue) {
return modifiedObject;
}


例1:------------------------------------
db.a.insert([
{_id:1,sku_id:1,stock:1},
{_id:2,sku_id:3,stock:2},
{_id:3,sku_id:2,stock:3},
{_id:4,sku_id:1,stock:4},
{_id:5,sku_id:2,stock:5},
])

var diy_map=function(){
emit(this.sku_id,this.stock)
}

var diy_reduce=function(k,v){
return Array.sum(v)
}

db.runCommand({
mapReduce:"a",//对应的collection名称
map:diy_map,
reduce:diy_reduce,
out:{inline:1}//在内存中执行
})

输出
---
/* 1 */
{
"results" : [
{
"_id" : 1.0,
"value" : 5.0
},
{
"_id" : 2.0,
"value" : 8.0
},
{
"_id" : 3.0,
"value" : 2.0
}
],
"timeMillis" : 23,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 3
},
"ok" : 1.0
}
---

如果把 return Array.sum(v) 换成 return {"my_k":k,"my_v":v} 则输出
---
/* 1 */
{
"results" : [
{
"_id" : 1.0,
"value" : {
"my_k" : 1.0,
"my_v" : [
1.0,
4.0
]
}
},
{
"_id" : 2.0,
"value" : {
"my_k" : 2.0,
"my_v" : [
3.0,
5.0
]
}
},
{
"_id" : 3.0,
"value" : 2.0
}
],
"timeMillis" : 24,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 3
},
"ok" : 1.0
}
---
如果想把结果输出放入一个collection 把 out:{inline:1} 缓存 out:"diy_document" 输出
out:{inline:1}输出内容的"result":[{.},{.},{.}]换成 "result":"diy_document"
---
/* 1 */
{
"result" : "c",
"timeMillis" : 40,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 3
},
"ok" : 1.0
}
---
diy_document内容为 out:{inline:1}输出result字段[]里的内容
---
/* 1 */
{
"_id" : 1.0,
"value" : {
"my_k" : 1.0,
"my_v" : [
1.0,
4.0
]
}
}

/* 2 */
{
"_id" : 2.0,
"value" : {
"my_k" : 2.0,
"my_v" : [
3.0,
5.0
]
}
}

/* 3 */
{
"_id" : 3.0,
"value" : 2.0
}
---

整合finalize

var diy_map=function(){
emit(this.sku_id,this.stock)
}

var diy_reduce=function(k,v){
return {"my_k":k,"my_v":v};
}

var diy_finalize=function(k,v){
v.diy_field="我是在diy_finalize添加的字段"
return {"my_k2":k,"my_v2":v};
}

db.runCommand({
mapReduce:"a",//对应的collection名称
map:diy_map,
reduce:diy_reduce,
finalize:diy_finalize,
out:{inline:1}//在内存中执行
})

输出
---
/* 1 */
{
"results" : [
{
"_id" : 1.0,
"value" : {
"my_k2" : 1.0,
"my_v2" : {
"my_k" : 1.0,
"my_v" : [
1.0,
4.0
],
"diy_field" : "我是在diy_finalize添加的字段"
}
}
},
{
"_id" : 2.0,
"value" : {
"my_k2" : 2.0,
"my_v2" : {
"my_k" : 2.0,
"my_v" : [
3.0,
5.0
],
"diy_field" : "我是在diy_finalize添加的字段"
}
}
},
{
"_id" : 3.0,
"value" : {
"my_k2" : 3.0,
"my_v2" : 2.0
}
}
],
"timeMillis" : 33,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 3
},
"ok" : 1.0
}
---