目录
mongoDB的常用操作符
mongoDB的聚合管道符号
db.collection.aggregate( [ { }, … ] )
使用aggregate()方法来构建和使用聚合管道。
比较操作符
- $eq“=” 等于
- $gt “>” 大于
- $gte”>=“ 大于等于
- $lt “<” 小于
- $lte ”<= “小于等于
- $ne ”!="不等于
- $in 相当于MySQL的in
- $nin相当于MySQL的nin
案例:db.<****CollectionName**>.find(**{ <field>: { $gt: <value> } })
逻辑运算符
- $or OR或相当于MySQL的OR
案例:
db.<****CollectionName**>**.find({ KaTeX parse error: Undefined control sequence: \[ at position 4: or:\̲[̲{<field\>:{ lt:<value>}},{<field>:<value>}], <field>:<value>})
limit 跳过指定数量的文档
skip 查询指定数量的文档
案例:
db.<****CollectionName**>**.find({}).skip(20).limlit(20)
注意注意注意
1. 区间查询
假如说我们查询一个年龄大于等于30,小于等于60的一定要采用 $and逻辑符号,这样查询;
正确案例:
db.<****CollectionName**>**.find({ KaTeX parse error: Undefined control sequence: \[ at position 4: and\̲[̲{age:{ gte:30}},{age:{$lte:60}}]})
或者:
db.<****CollectionName**>**.find({age:{ g t e : 30 , gte:30, gte:30,lte:60}})
错误案例:(这种他不是区间查询,age大于等于30和小于等于60的都会查询出来)
db.<****CollectionName**>**.find({age:{ KaTeX parse error: Expected 'EOF', got '}' at position 7: gte:30}̲,age:{ lte:60}})
2.NumberLong类型强转
Mongo的NumberLong类型查询要强转。
假如说我们age字段是NumberLong类型的。查询的时候需要强转一下,不然呢查询不到
正确案例:
db.heartBpmHistory.find({age:{ g t e : N u m b e r L o n g ( ′ 3 0 ′ ) , gte:NumberLong('30'), gte:NumberLong(′30′),lte:NumberLong(‘60’)}})
错误案例一:
db.<****CollectionName**>**.find({age:{ g t e : 30 , gte:30, gte:30,lte:60}})
错误案例二:
db.heartBpmHistory.find({age:{ g t e : N u m b e r L o n g ( 30 ) , gte:NumberLong(30), gte:NumberLong(30),lte:NumberLong(60)}})
数学运算符
- $add加法
- $subtract 减法
- $multiply 乘法
- $divide 除法
- $mod 求余
mongoDB案例
插入测试数据
db.student22.insertMany([{
“name”: “张0”,
“gender”: “女”,
“age”: 0,
“math”: NumberInt(84),
“language”:NumberInt(99),
“classes”: “一年级二班”,
“Hobby”: [“蓝色”,“蓝色1”,“蓝色2”]
},{
“name”: “张1”,
“gender”: “男”,
“age”: 1,
“math”: NumberInt(42),
“language”: NumberInt(48),
“classes”: “一年级二班”,
“Hobby”: [“绿色”,“绿色1”,“绿色2”]
},{
“name”: “张2”,
“gender”: “女”,
“age”: 2,
“math”: NumberInt(71),
“language”: NumberInt(33),
“classes”: “一年级一班”,
“Hobby”: [“青色”,“青色1”,“青色2”]
},{
“name”: “张3”,
“gender”: “男”,
“age”: 3,
“math”: NumberInt(93),
“language”: NumberInt(2),
“classes”: “一年级一班”,
“Hobby”: [“黄色”,“黄色1”,“黄色2”]}])
下面的Java案例中关于mongodb操作的类皆来与
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.junit4.SpringRunner;包中,请注意引包问题
mongodb的阶段操作符号
所用的案例都是用的上面插入的数据
- $match:
格式: {$match:field:value\}
介绍: 指定某个字段的查询条件,相当于MySQL中的where
案例:
筛选math大于30,language小于100的信息
//可以结合上面的比较运算符,数学运算符,逻辑运算符操作 db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}} ])??????
-------------------------------------------------------------------------------------------------------------------------
- $count
格式:{$count : <field>}
介绍: 返回总条数; 等价于MySQL中的count函数
案例:
筛选math大于30,language小于100的总记录数
db.student22.aggregate([ ? ? ??{$match:{classes:"一年级一班",math:{$gt:60},language:{$lt:80}}}, {$count:"name"} ])???
-------------------------------------------------------------------------------------------------------------------------
- $group
格式:
{$group:{_id:<Field>, <field1>: { <accumulator1> : <expression1> }}}
介绍:
使用该阶段符分组查询
该
<accumulator>
运算符必须是以下累加器运算符之一 (案例中有介绍)字段名称前加一个美元符号
$
并用引号引起来案例:
筛选math大于30,language小于100的记录, 根据classes字段分组查询,求出每个分组math字段的和.
//第一种方式,_id会被覆盖 db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, //$sum:1 则会返回每个分组的总记录数 {$group:{_id:"$classes",mathCount:{$sum:"$math"},id:{$last:"$_id"},name:{$last:"$name"},gender:{$first:"$gender"}}}, ]) //第二种id不会别覆盖的方式 db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, //$sum:1 则会返回每个分组的总记录数 {$group:{_id:"$classes",data:{$first:"$$ROOT"}}}, {$replaceRoot: { newRoot: "$data" }}, ]) /** ---------------累加器运算符--------------------------------------------- $addToSet 返回每个组的唯一表达式值的数组。数组元素的顺序未定义。 $avg 返回数值的平均值。忽略非数字值。 $first 从每个组的第一个文档返回一个值。仅当文档按定义的顺序定义顺序。 $last 从每个组的最后一个文档返回一个值。仅当文档按定义的顺序定义顺序。 $max 返回每个组的最高表达式值。 $mergeObjects 返回通过组合每个组的输入文档而创建的文档。 $min 返回每个组的最低表达式值。 $push 返回每个组的表达式值数组。 $stdDevPop 返回输入值的总体标准偏差。 $stdDevSamp 返回输入值的样本标准偏差。 $sum 返回数值的总和。忽略非数字值。 **/ //java代码实现 @Autowired private MongoTemplate mongoTemplate; public void mongoGroupTest(){ Aggregation aggregation = Aggregation.newAggregation( //先筛选 Aggregation.match(Criteria.where("math").gt(30).and("language").lt(100)), //加入我们要娶每组中最大的一条记录,就可以先在这里倒叙,然后去第一天记录 Aggregation.sort(Sort.Direction.DESC,"排序字段"), //在分组 Aggregation.group("classes").first("$$ROOT").as("data"), //然后复原 Aggregation.replaceRoot().withValueOf("data") ); //查询 AggregationResults<AttackSecurityEntity> aggregate = mongoTemplate.aggregate(aggregation, "你的表名", 实体类名.class); List<AttackSecurityEntity> results = aggregate.getMappedResults();//获取数据 }
- $replaceRoot
介绍:
将嵌套的数据提取出来,
<replacementDocument>一定要是个对象字段,或者没有该字段都会报错
格式:{ $replaceRoot: { newRoot: <replacementDocument> } }
案例:
//插入测试数据 db.demo10.insert({ name:"测试$replaceRoot符的数据", data:{ id:NumberInt(123), name:"张上", age:NumberInt(12) } }) //demo01中嵌套了一个对象叫data,假如说我们的需求就只需要data对象, //那么我们可以使用$replaceRoot阶段符号实现 //Mongo语句实现 db.demo10.aggregate( [ { $replaceRoot: { newRoot: "$data" } } ] ) //Java案例在group案例中有实现
-------------------------------------------------------------------------------------------------------------------------
- $project
格式: {$project:field:0:1,field}
介绍: 指定哪些字段进入下阶段管道,或者返回。0:false ,1:true
案例:
接着上面的分组案例往下来,我们排除name和gender字段不接收
db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, {$group:{_id:"$classes",mathCount:{$sum:"$math"},id:{$last:"$_id"},name:{$last:"$name"},gender:{$first:"$gender"}}}, {$project:{name:0,gender:0}} //字段:0 表示排除他 ])??? //Java案例在group案例中有实现
-------------------------------------------------------------------------------------------------------------------------
- $addFields
格式: {$addFields:<newField>:<value>}
介绍:
将新字段添加到文档。
$addFields
输出包含输入文档中所有现有字段和新添加的字段的文档 . 字段名称前加一个美元符号
$
并用引号引起来案例:
新加一个nowField字段.并且为每组的总分(mathCount字段)加1
db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, {$group:{_id:"$classes",mathCount:{$sum:"$math"},id:{$last:"$_id"},name:{$last:"$name"},gender:{$first:"$gender"}}}, {$project:{name:0,gender:0}}, //每个条记录都会增加nowField这个文档, 每条记录的mathCount都会加1 {$addFields:{nowField:"我是新加的字段",mathCount:{$add:["$mathCount",1]}}} ])???
-------------------------------------------------------------------------------------------------------------------------
- $sort
格式: {$sort:{ <field1>: , <field2>: … }}
介绍: 排序符, -1 表示倒叙, 1表示正序
案例:
为总分(mathCount字段) 倒叙排序.
db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, {$group:{_id:"$classes",mathCount:{$sum:"$math"},id:{$last:"$_id"},name:{$last:"$name"},gender:{$first:"$gender"}}}, {$project:{name:0,gender:0}}, //每个条记录都会增加nowField这个文档, 每条记录的mathCount都会加1 {$addFields:{nowField:"我是新加的字段",mathCount:{$add:["$mathCount",1]}}}, {$sort:{mathCount:-1}} ])? //Java的代码实现请往下看
- $set
格式: {$set:<newField>:<value>}
介绍:
将新字段添加到文档。
$set
输出包含输入文档中所有现有字段和新添加的字段的文档。$set 和 a d d F i e l d s 这两个阶段等效于一个 addFields这两个阶段等效于一个 addFields这两个阶段等效于一个project阶段.
字段名称前加一个美元符号
$
并用引号引起来-------------------------------------------------------------------------------------------------------------------------
- $redact
格式: { $redact: <expression> }
介绍:
根据条件限制文档的内容。
案例:
跟着上面的案例继续聚合, 使用$redact符筛选出mathCount字段大于160的数据
db.student22.aggregate([ ? ? ??{$match:{math:{$gt:30},language:{$lt:100}}}, {$group:{_id:"$classes",mathCount:{$sum:"$math"},id:{$last:"$_id"},name:{$last:"$name"},gender:{$first:"$gender"}}}, {$project:{name:0,gender:0}}, {$addFields:{nowField:"我是新建的字段",mathCount:{$add:["$mathCount",1]}}}, {$redact:{ $cond:{ if:{ $gt:["$mathCount",160]}, then:"$$KEEP", else:"$$PRUNE" }}} ]) /**then 和 else 可以是任何有效表达式,只要它解析为$$ DESCEND, $$ PRUNE或$$ KEEP系统变量即可。 $$ DESCEND : $redact返回当前文档级别的字段,不包括嵌入式文档。要将嵌入式文档和嵌入式文档包含在数组中,请将$cond 表达式应用于嵌入式文档,以确定对这些嵌入式文档的访问。 $$ KEEP: $redact返回或将所有字段保留在当前文档/嵌入式文档级别,而无需进一步检查此级别的字段。即使所包含的字段包含可能具有不同访问级别的嵌入式文档,这也适用。 $$PRUNE: $redact在当前文档/嵌入文档级别排除所有字段,而无需进一步检查任何排除的字段。即使排除字段包含具有不同访问级别的嵌入式文档,这也适用。 **/ //Java代码实现 @Autowired private MongoTemplate mongoTemplate; @Test public void mongoTest(){ //构造$redact的条件 ConditionalOperators.Cond cond = ConditionalOperators.Cond.when(ComparisonOperators.Gt.valueOf("mathCount").greaterThanValue(160)).then("$$KEEP").otherwise("$$PRUNE"); Aggregation aggregation = Aggregation.newAggregation( //先筛选 Aggregation.match(Criteria.where("math").gt(30).and("language").lt(100)), //在分组 Aggregation.group("classes").sum("$math").as("mathCount").last("_id").as("id").last("name").as("name"), //追加字段 Aggregation.addFields().addField("nowField").withValue("我是新建的字段").addFieldWithValue("mathCount", ArithmeticOperators.Add.valueOf("mathCount").add(1)).build(), //排除字段 Aggregation.project().andExclude("name","gender"), Aggregation.redact(cond) ); //查询 AggregationResults<AttackSecurityEntity> aggregate = mongoTemplate.aggregate(aggregation, "你的表名", 实体类名.class); List<AttackSecurityEntity> results = aggregate.getMappedResults(); } ?
-------------------------------------------------------------------------------------------------------------------------
- $lookup
格式:
{
$lookup:
{
from: ,
localField: ,
foreignField: <field from the documents of the “from” collection>,
as:
}
}介绍:
关联查询
使用该操作符实现表之间的关联查询
案例:
//插入parent22表,与上面的student22表关联, //关联的字段是name,关联的字段名可以不同,但是值必须相同,丛主表关联的字段类型必须相同(除数组类型外) db.parent22.insertMany([ {name:"张0",mobile:1304444444,parentName:"张0的爸爸"}, {name:"张1",mobile:1374444444,parentName:"张1的爸爸"}, {name:"张0",mobile:1594444444,parentName:"张0的妈妈"}, {name:"张1",mobile:1864444444,parentName:"张1的妈妈"}, ]) //mongo查询案例 db.student22.aggregate([ {$lookup:{ from:"parent22", //关联从表的表名 localField:"name", //主表关联的字段 foreignField: "name", //从表关联的字段(从表类型也可以是数组). as:"pr" //给结果起个别名 } } ]) //假如说我们关联查询时候就要加条建 db.student22.aggregate([ {$lookup:{ from:"parent22", //关联从表的表名 let: { nm: "$name", // 定义要筛选的字段 }, pipeline: [{ $match: { $expr: { $eq: ["张1","$name"] // 筛选从表name等于张1的信息 } }, } //下面还可以继续指定其他管道阶段符合 ], as:"pr" //给结果起个别名 } } ]) //java实现的案例 @Autowired private MongoTemplate mongoTemplate; @Test public void mongoTest(){ Aggregation aggregation = Aggregation.newAggregation(Aggregation.lookup("从表表名", "主表关联字段名", "从表关联字段", "结果起的别名")); AggregationResults<Test> result = mongoTemplate.aggregate(aggregation, "你的表名", Test.class); //获取结果 List<Test> mappedResults = result.getMappedResults(); } //mongo查询返回的结果 { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95e"), "name" : "张0", "gender" : "女", "age" : 4.0, "math" : NumberInt(84), "language" : NumberInt(99), "classes" : "一年级二班", "Hobby" : ["蓝色", "蓝色1", "蓝色2"], "pr" : [ { "_id" : ObjectId("623151398a0c4bd7d10ac962"), "name" : "张0", "mobile" : 1304444444.0, "parentName" : "张0的爸爸" }, { "_id" : ObjectId("623151918a0c4bd7d10ac966"), "name" : "张0", "mobile" : 1304444444.0, "parentName" : "张0的爸爸" }, { "_id" : ObjectId("623151918a0c4bd7d10ac968"), "name" : "张0", "mobile" : 1594444444.0, "parentName" : "张0的妈妈" } ] } { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95f"), "name" : "张1", "gender" : "男", "age" : 1.0, "math" : NumberInt(42), "language" : NumberInt(48), "classes" : "一年级二班", "Hobby" : [ "绿色", "绿色1", "绿色2" ], "pr" : [ { "_id" : ObjectId("623151398a0c4bd7d10ac963"), "name" : "张1", "mobile" : 1374444444.0, "parentName" : "张1的爸爸" }, { "_id" : ObjectId("623151918a0c4bd7d10ac967"), "name" : "张1", "mobile" : 1374444444.0, "parentName" : "张1的爸爸" }, { "_id" : ObjectId("623151918a0c4bd7d10ac969"), "name" : "张1", "mobile" : 1864444444.0, "parentName" : "张1的妈妈" } ] } { "_id" : ObjectId("62303f0c8a0c4bd7d10ac960"), "name" : "张2", "gender" : "女", "age" : 2.0, "math" : NumberInt(71), "language" : NumberInt(33), "classes" : "一年级一班", "Hobby" : [ "青色", "青色1", "青色2" ], "pr" : [ { "_id" : ObjectId("623151398a0c4bd7d10ac964"), "name" : "张2", "mobile" : 1594444444.0, "parentName" : "张2的爸爸" } ] } { "_id" : ObjectId("62303f0c8a0c4bd7d10ac961"), "name" : "张3", "gender" : "男", "age" : 3.0, "math" : NumberInt(93), "language" : NumberInt(2), "classes" : "一年级一班", "Hobby" : [ "黄色", "黄色1", "黄色2" ], "pr" : [ { "_id" : ObjectId("623151398a0c4bd7d10ac965"), "name" : "张3", "mobile" : 1864444444.0, "parentName" : "张3的爸爸" } ] }
-------------------------------------------------------------------------------------------------------------------------
- $unwind
格式: {$unwind :<arrayField>}
介绍:
拆分数组,数组中的每个数据都会生成一条记录.
字段名称前加一个美元符号
$
并用引号引起来案例:
查询name等于"张0"的记录,该记录中有个Hobby字段是数组类型,将该数组拆分
db.student22.aggregate([ {$match:{name:"张0"}}, {$unwind:"$Hobby"} ]) /** 未拆分的数据: { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95e"), "name" : "张0", "gender" : "女", "age" : 0.0, "math" : NumberInt(84), "language" : NumberInt(99), "classes" : "一年级二班", "Hobby" : [ "蓝色", "蓝色1", "蓝色2" ] } 拆分后的数据: { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95e"), "name" : "张0", "gender" : "女", "age" : 0.0, "math" : NumberInt(84), "language" : NumberInt(99), "classes" : "一年级二班", "Hobby" : "蓝色" } { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95e"), "name" : "张0", "gender" : "女", "age" : 0.0, "math" : NumberInt(84), "language" : NumberInt(99), "classes" : "一年级二班", "Hobby" : "蓝色1" } { "_id" : ObjectId("62303f0c8a0c4bd7d10ac95e"), "name" : "张0", "gender" : "女", "age" : 0.0, "math" : NumberInt(84), "language" : NumberInt(99), "classes" : "一年级二班", "Hobby" : "蓝色2" } **/
-------------------------------------------------------------------------------------------------------------------------
- $geoNear
格式: {$geoNear:<geoNear options>}
介绍:
指定经纬度点,从mongodb中查询,最近到最远的顺序输出文档。
案例:参考这里
-------------------------------------------------------------------------------------------------------------------------
- $bucket
格式:
{
KaTeX parse error: Undefined control sequence: \[ at position 58: … boundaries: \̲[̲ <lowerbound1>,…accumulator expression> },
: { <$accumulator expression> }
}
}
}介绍:
根据自定义条件分组
案例:
根据年龄区间分组
db.student22.aggregate([ {$bucket:{ groupBy: "$age", //根据age字段分组 boundaries:[1,4], //年龄再1到4之间(左开右闭.包含1,不包含4)的分一个组 default: "Other", //没有达到条件的分一个组 output:{ "student22":{ $push:{ "age":"$age" //这里表示将分组后的所有年龄数组 } } } }} ]) //对应的Java代码 --------------------------------------------------------------------------> import org.springframework.data.mongodb.core.MongoTemplate; @Autowired private MongoTemplate mongoTemplate; @Test public void mongoTest(){ Aggregation newAggregation = Aggregation.newAggregation( Aggregation.bucket("age") .withDefaultBucket("other") .withBoundaries(1, 4) .andOutput("age") .push().as("student22") ); AggregationResults<Test> result = mongoTemplate .aggregate(newAggregation, "你的表名", 实体类.class); //获取结果 List<Test> mappedResults = result.getMappedResults(); }
springBoot整合mongoDB
pom依赖
org.springframework.boot spring-boot-starter-data-mongodb
yml配置
spring:
data:
mongodb:
uri: mongodb://用户名:密码@IP:端口/数据库名字authSource=admin&authMechanism=SCRAM-SHA-1
java代码案例
@Autowired
private MongoTemplate mongoTemplate;
public void mongoTest(){
ConditionalOperators.Cond condition = ConditionalOperators.Cond.when((Criteria.where("表中的字段名1").is("等于的值"))).thenValueOf("").otherwiseValueOf("");
//在这里构造我们的聚合条件
Aggregation aggregation = Aggregation.newAggregation(
//根据自己的业务构造自己的条件
Aggregation.match(Criteria.where("表中的字段名1").is("等于的值").and("表中的字段名2").in("等于的值")),
Aggregation.group("要分组的字段名").first("表中的字段名").as("起的别名"),
Aggregation.project().andExclude("排除的字段").andInclude("包含的字段"),
Aggregation.addFields().addField("nowField").withValue("新建的字段").build().and().addField().withValueOfExpression("a", 1, 2).build(),
Aggregation.unwind("表中数组字段名"),
Aggregation.redact(condition)
);
//查询
AggregationResults<Test> result = mongoTemplate.aggregate(aggregation, "你的表名", Test.class);
//获取结果
List<Test> mappedResults = result.getMappedResults();
}
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦