基本语法
mongoDB 聚合查询语法,这些命令均在 Aggregation 中实现
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match : 用于过滤数据,只输出符合条件的文档 。match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。
注解名称 | 作用对象 | 功能 |
---|---|---|
@Document | right-aligned 文本居右 | 类似于 hibernate 的 entity 注解,标明由 mongo 来维护该表 |
@CompoundIndex | 实体类 | 复合索引 |
@Id | 实体类 | 和 mongoDB 中 _id 字段对应 |
@Field | 字段 | 可以通过该注解自定义在 mongo 中的名称 |
@Indexed | 字段 | 声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度 |
@Transient | 字段 | 表示该字段不在 mongo 中存储,既忽略该字段 |
Book表
[{_id:“1”},“orderId”:“2022-1”,“name”:“胡聪1”,dateTime:“1650991481030”,“status”:0},
{_id:“2”},“orderId”:“2022-2”,“name”:“胡聪1”,dateTime:“1650991481040”,“status”:1},
{_id:“3”},“orderId”:“2022-3”,“name”:“胡聪3”,dateTime:“1650991481050”,“status”:1},
{_id:“4”},“orderId”:“2022-4”,“name”:“胡聪4”,dateTime:“1650991481060”,“status”:0}]
BookStatus表
[{_id:“100”},“orderId”:“2022-1”,“bookId”:“1”,“status”:0},
{_id:“200”},“orderId”:“2022-2”,bookId":“2”,“status”:1]
基本查询
1. find
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key> :<value> } | db.col.find({“name”:“胡聪1”}).pretty() | where name = ‘胡聪1’ |
小于 | {<key>: {$lt:<value> }} | db.col.find({“dateTime”:{$lt:1650991481030}}).pretty() | where dateTime < 1650991481030 |
小于或等于 | {<key> :{$lte:<value> }} | db.col.find({“dateTime”:{$lte:1650991481030}}).pretty() | where dateTime <= 1650991481030 |
大于 | {<key> :{$gt:<value> }} | db.col.find({“dateTime”:{$gt:1650991481030}}).pretty() | where dateTime > 1650991481030 |
大于或等于 | {<key> :{$gte:<value> }} | db.col.find({“dateTime”:{$gte:1650991481030}}).pretty() | where dateTime >= 1650991481030 |
不等于 | {<key> :{$ne:<value> }} | db.col.find({“dateTime”:{$ne:1650991481030}}).pretty() | where dateTime != 501650991481030 |
- AND
db.col.find({key1:value1, key2:value2}).pretty()
查询名字为胡聪且状态为0的数据
db.book.find({"name":"胡聪", "status":"0"}).pretty()
- OR
db.col.find({$or: [ {key1: value1}, {key2:value2}]}).pretty()
查询名字为胡聪或者状态为0的数据
db.book.find({$or:[{"name":"胡聪"},{"status": "0"}]}).pretty()
- OR 和 AND 联合使用 :查询dateTime>1650991481030且名字为胡聪或状态为0的数据
db.book.find({ "dateTime": { // and $gt:1650991481030 }, $or: [ //or { "name": "胡聪" }, { "staus": "0" } ] }).pretty()
- 比较查询
- 大于> / 小于< 查询时间大于1650991481030小于1650991481050
db.book.find({dateTime: {$lt :1650991481050, $gt : 1650991481030}})
- 大于> / 小于< 查询时间大于1650991481030小于1650991481050
聚合查询
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 将值加入一个数组中,不会判断是否有重复的值。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
分组统计:select order_name, count(*) from bookDetail group by order_name
- 查询bookDetail表中统计相同order_name的个数
db.bookDetail.aggregate([{ $group: { _id: "$order_name", totalCount: { $sum: 1 } } }])
案例1. 类似not in的实现
关联查询出Book表前1000条数据,但不包括BookStatus中BookId = Book._id的数据
db.book.aggregate([ //指定主表
{
$lookup: {
from: 'bookStatus', //指定从表
as: 'class', //从表数据别名
localField: '_id', //主表关联字段
foreignField: 'bookId' //从表关联字段
}
},
{
$match: {
'class._id': {
$exists: false //排除符合条件的从表数据
}
}
},
{$project:{
name:1, //主数据字段显示(1显示 0隐藏)
_id:1, //主数据字段显示
orderId:1, //主数据字段显示
dateTime:1, //主字段显示
consumerStatus:"$class.status", //从数据值别名
bookId:"$class.bookId" //从数据值别名
}
},
{$sort: {dateTime: 1}}, //1(升序)和-1(降序
{$skip: 0 //分页起始},
{$limit: 1000 //分页个数}
])
Java写法:
public void selectUndoByPage(){
//构造聚合函数
Aggregation aggregation = Aggregation.newAggregation(LookupOperation.newLookup()
.from("bookDetail") //指定从表
.localField("_id") //主表关联字段
.foreignField("bookId") //从表关联字段
.as("class"), //从表数据别名
Aggregation.match(Criteria
.where("class._id") //排除符合条件的从表数据
.exists(false)),
Aggregation.project("orderId", "_id", "address", "order_Name", "className", "createTime","class.consumerStatus", "class.bookId"), //显示字段
Aggregation.sort(Sort.Direction.ASC, "createTime"), //排序
Aggregation.skip(0L), //分页
Aggregation.limit(1000)); //分页
List<Book> list = mongoTemplate.aggregate(aggregation, "book", Book.class).getMappedResults();
list.forEach(System.out::println);
}
输出:
[{"name":"胡聪3",_id:"3","orderId":"2022-3",dateTime:"1650991481050","consumerStatus":null,"bookId"=null},
{"name":"胡聪4",_id:"4","orderId":"2022-4",dateTime:"1650991481060","consumerStatus":null, "bookId"=null}]]
注意:
$sort
和$lookup
里面的字段建议设置为索引