MongoDB知识整理
一 简介
MongoDB属于NoSQL是非关系型数据库。
关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据。
1.2MySQL与MongoDB之间最基本的差别是什么?
MySQL和MongoDB两者都是免费开源的数据库。MySQL和MongoDB有许多基本差别包括数据的表示(data representation),查询,关系,事务,schema的设计和定义,标准化(normalization),速度和性能。
1.3MongoDB的优势有哪些
面向文档的存储:以 JSON 格式的文档保存数据。
架构简单
没有复杂的连接
深度查询能力,MongoDB支持动态查询。
容易调试
容易扩展
不需要转化/映射应用对象到数据库对象
使用内部内存作为存储工作区,以便更快的存取数据。
1.4mongodb和关系型数据库术语对比
1.5MongoDB支持哪些数据类型
String、Integer、Double、Boolean、Object、Object ID、Arrays、Min/Max Keys、Datetime、Code、Regular Expression等。
二基本语法
2.1插入索引、查看索引、删除索引
创建一个索引
db.collection.createIndex(keys, options)
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可db.col.createIndex({"title":1})
db.col.createIndex({"title":1,"description":-1})
查看集合索引
db.col.getIndexes()
查看集合索引大小
db.col.totalIndexSize()
删除集合所有索引
db.col.dropIndexes()
删除集合指定索引
db.col.dropIndex("索引名称")
2.2插入insert
插入单条数据
db.col.insert({name:"java",age:"保密",author:null})
插入带数组的数据
db.col.insert({name:".net",age:88,author: ["xiaoxu","xiaozhang","xiaoliu"]})
插入多条数据
db.col.insert([{name:"序员修炼之旅",age:2,from: "CTU"},
{name: "mongdo",age:13,from: "USA"},
{name: "C++",from: "USA" ,author:["xiaoxu","xiaozhang"]}])
2.3更新update
db.collectionName.update({key:value},{$set:{newkey:newValue}})
如db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
2.4删除delete
db.collectionName.remove({key:value})
如db.col.remove({'title':'MongoDB 教程'})
2.5查找find
语法格式
db.collection.find(query, projection)
$and
db.col.find({"by":"菜鸟教程", "title":"MongoDB 教程"})
$or
db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]})
db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]})
大于小于
db.posts.find( { qty: { $gt: 50 ,$lt: 80}} )
$lt小于
db.col.find({"likes":{$lt:50}})
$lte小于等于
db.col.find({"likes":{$lte:50}})
$gt大于
db.col.find({"likes":{$gt:50}})
$gte大于等于
db.col.find({"likes":{$gte:50}})
$ne不等于
db.col.find({"likes":{$ne:50}})
2.6子文档操作
db.getCollection("ProjectInfo").find({FormValues:{$elemMatch:{value:"0011"}}})
查询ProjectNumber":"0011"和子文档里FormValues.key的值为"1536130777269",修改FormValues.$.value的值为"0011"
db.getCollection("ProjectInfo").update(
{"ProjectNumber":"0011","FormValues.key": "1536130777269"},
{$set:{"FormValues.$.value":"0011"}}
);
2.7关于null的查询
查询集合c中y的值为null或者不存在
>db.col.find( { “y” : null } )
查询集合c中y的值为null,(仅返回y的值为null的数据,不会返回不存在的)
>db.col.find( { “y” : { $type : 10 } } )
还有一种写法如下
>db.col.find({“y”:{“$in”:[null], “$exists”:true}})
查询集合c中y的值不存在(不会返回y的值为null的数据)
>db.col.find( { “y” : { $exists : false } } )
查询集合c中y的值不为null且存在的记录
>db.col.find( { “y” : {"$ne":null, $exists: true }} )
或者:>db.col.find( { “y” : {"$ne":null }} )
三聚合语法
3.1阶段操作符
$project
修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
只查询ProjectState属性 1为显示 0为不显示 _id默认显示
db.getCollection("PI_ProjectInfo").aggregate({$project:{ProjectState:1,_id:0}});
只显示ProjectState:1集合的ProjectState属性
db.getCollection("PI_ProjectInfo").aggregate({$match:{ProjectState:1}},{$project:{ProjectState:1,_id:0}});
$match
用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
查询ProjectName是"0011"的集合
db.getCollection("PI_ProjectInfo").aggregate({$match:{ProjectName:"0011"}});
查询ProjectState>1的集合
db.getCollection("PI_ProjectInfo").aggregate({$match:{ProjectState:{$gt:1}}});
当 match 条件和 group 同时存在时,顺序会影响检索结果,必须先写 match 在前面。
$limit
用来限制MongoDB聚合管道返回的文档数。
db.getCollection("PI_ProjectInfo").find().limit(5)
或者
db.getCollection("PI_ProjectInfo").aggregate({$match:{ProjectState:1}},
{$project:{_id:1}},
{$sort:{_id:1}},
{$limit:5}
);
$skip
在聚合管道中跳过指定数量的文档,并返回余下的文档。
分页,跳过1条取3条
db.collection.find(查询条件).sort(排序方式).skip((页码-1)*每页数据条数).limit(每页数据条数)
db.getCollection("PI_ProjectInfo").find().limit(3).skip(1)
查询ProjectState为1并以id分页的第二页数据的id
db.getCollection("PI_ProjectInfo").aggregate({$match:{ProjectState:1}},
{$sort:{_id:1}},
{$skip:1},{$limit:2},
{$project:{_id:1}},
);
$unwind
将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
查询子文档里FormValues.value的值为"0011",显示ProjectNumber和嵌套文档FormValues
db.getCollection("PI_ProjectInfo").aggregate({$unwind:{path:"$FormValues"}},{$match:{"FormValues.value":"0011"}},
{$project:{"ProjectNumber":1,"FormValues":1,_id:0}});
结果
// 1
{
"ProjectNumber": "0011",
"FormValues": {
"key": "ProjectName",
"value": "0011"
}
}
// 2
{
"ProjectNumber": "0011",
"FormValues": {
"key": "ProjectNumber",
"value": "0011"
}
}
$group
将集合中的文档分组,可用于统计结果。
_id值必须的,分组依据,在分组中可以使用$sum,$avg等子聚合操作
以ProjectState分组统计数量
db.getCollection("ProjectInfo").aggregate(
{$group:{_id:"$ProjectState",count:{$sum:1}}}
);
统计MemberType列数值总和
db.test.aggregate({$group:{_id:null,a:{$sum:"$MemberType"}}})
$sort:将输入文档排序后输出。
以CreateDate正序并且以_id倒序查询,1为正序 -1 为倒序
db.getCollection("ProjectInfo").aggregate({$sort:{CreateDate:1,_id:-1}});
查询ProjectState为1集合的id属性,并与id属性倒序
db.getCollection("ProjectInfo").aggregate({$match:{ProjectState:1}},
{$project:{_id:1}},
{$sort:{_id:1}});
$geoNear
输出接近某一地理位置的有序文档。
$count
统计操作符,用于统计文档的数量
db.getCollection("PI_ProjectInfo").aggregate(
{$match:{ProjectState:1}},
{$count:"count"},
);
$lookup
连接操作符,用于连接同一个数据库中另一个集合,并获取指定文档
$lookup:{ from:<要连接的表>, localField:<当前表的属性>, foreignField:<连接表的属性> as:<新的数组属性> }}
连表查询签字确认和签字确认成员表 db.getCollection('DC_ApprovalSignature').aggregate({
$lookup:{
from:"DC_ApprovalMember",
localField:"_id",
foreignField:"ASId",
as:"DC_ApprovalMember"
}
},{$unwind:"$DC_ApprovalMember"})
db.getCollection('ApprovalSignature').aggregate(
{$lookup:{
from:"ApprovalMember",
localField:"_id",
foreignField:"ASId",
as:"ApprovalMember"
}
})
$AddFields
向文档中添加新字段,输出包含来自输入文档和新添加字段的所有现有字段文档
{$addFields:{<newField>:<expression>,...}}
查询时添加一列(子文档中UserOrder的和) db.getCollection('DC_ProjectInformation').aggregate({$addFields:{subUserOrder:{$sum:"$ProjectMembers.UserOrder"}}})
只查询添加的一列(子文档中UserOrder之和) db.getCollection('DC_ProjectInformation').aggregate({$addFields:{subUserOrder:{$sum:"$ProjectMembers.UserOrder"}}},{$project:{subUserOrder:1,_id:0}})
向嵌入文档中添加一列 newFiled db.getCollection('DC_ProjectInformation').aggregate({$addFields:{"ProjectMembers.newFiled":"newFiled"}})
$facet
将两个不同的聚合函数放在一起,进行结果展示
db.getCollection("222-LogSiteStatistics-2020").aggregate([
{$facet:{
"最快100":[
{$sort:{"FastestMilliseconds": 1}},
{$project:{_id:0,SiteName:1,FastestMilliseconds:1,FastestAPIAddress:1}},
{$limit:10}
],
"最慢100":[
{$sort:{"SlowestMilliseconds": -1}},
{$project:{_id:0,SiteName:1,SlowestMilliseconds:1,SlowestAPIAddress:1}},
{$limit:10}
]
}}
])
3.2表达式操作符
$and 表达式全部为true 返回true ,否则false
{$and:[<expression1>,<expression2>,....]}
$or {$or:[<expression1>,<expression2>,....]}
$eq 比较两个值返回true或false {$eq:[<expression1>,<expression2>]}
$ifNull 计算表达式,如果表达式计算为非null,则返回表达式值,如果表达式为null(包括未定义或缺少字段),则返回替换表达式的值
$cond 计算Boolean表达式以返回指定的返回表达式之一
{$cond:[<boolean-expression>,<true-case>,<false-case>]}
获取表中ApprivakState属性,1则输出true,其它输出false
db.getCollection('DC_ApprovalSignature').aggregate({ $project:{_id:1,ApprovalState:{$cond:{if:{$eq:["$ApprovalState",1]},then:"true",else:"false"}}}})
$in 返回一个boolean值,指示指定数值是否在数组中
db.user.find({from: {$in:[ "CTU","USA"]}})
$not 计算布尔值 ,返回相反的布尔数值
累加器
$sum,$avg,$first,$last,$max,$min
只能在$group和$project中使用
如果在包含数字和非数字值的字段上使用,则 $sum忽略非数字值并返回数字总和。如果用于集合中任何文档中都不存在的字段,则 $sum返回0该字段。如果所有操作数均为非数字,则$sum返回0。
3.3一些特殊的用法
分组 TopN的写法
通过调整$slice里的值来获取topN的数据。
如果想分组显示,则去掉$unwind和$replaceRoot语句即可。
db.getCollection("LogSiteStatistics").aggregate([
{$sort: {FastestMilliseconds: 1} },
{$group: {_id: '$SiteName',records: {$push: '$$ROOT'}}},
{$project: {_id: 0,SiteName: "$_id",
records: {$slice: ['$records',1]} },
},
{
"$unwind": "$records"
},
{
"$replaceRoot": {
"newRoot": "$records"
},
}
]);
对某一列的sum
db.getCollection("LogSiteStatistics").aggregate([
{"$match":{"SiteName":"开发WebAPI"}},
{"$group":{_id:"$SiteName",sumFaceAmnt:{"$sum":"$Frequency"}}},
//{$match:{sumFaceAmnt:{$lt:100}}}
])