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

基础了解

对应关系 -> 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

基本查询操作

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

// 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({})//清空表数据

查询

查询

比较查询操作符 -> 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}}

更新

更新

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"}}}

数组

数组

$ -> { "<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表示在开头添加 大于元素个数表示在最后追加

增删改查

增删改查

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);
}

索引创建

索引创建

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})

索引管理

索引管理

//插入自定义时间
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 分布式文件系统

GridFS 分布式文件系统

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

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

默认localhost:27017
--host

默认27017
--port

指定数据库
--db

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

聚合管道

聚合管道 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

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
}
---
posted on 2019-10-16 13:04  陶攀峰  阅读(243)  评论(0编辑  收藏  举报

顶部 底部