mongodb的多表联查与后续的数据处理
2019-06-14 11:48
1016 查看
版本
mongodb:3.6
spring:5.0.7
spring-data:2.0.7
mongo-java-driver:3.6.3
版本问题需要注意一下,如果版本不兼容会出现:The ‘cursor’ option is required, except for aggregate…的问题,解决办法是升级版本,spring-data2.x的运行环境是spring5.x以及jdk8+,mongodb-java-driver也应该升级到3.6以上
数据
user表
{ "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.UserBo" }
orders表
/* 1 */ { "_id" : ObjectId("5b69062240a6d80a6cece004"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 10.0, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "produce" : "产品1", "_class" : "com.xiangpeng.bo.OrderBo" } /* 2 */ { "_id" : ObjectId("5b6a5711c2eee4295c63768e"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 20.0, "produce" : "产品2", "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.OrderBo" }
查询
1.mongodb的多表查询比较简单,使用$lookup关键字即可:
db.user.aggregate([{$lookup:{from:"orders",localField:"_id",foreignField:"uid",as:"orders"}}])
结果:
{ "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.UserBo", "orders" : [ { "_id" : ObjectId("5b69062240a6d80a6cece004"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 10.0, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "produce" : "产品1", "_class" : "com.xiangpeng.bo.OrderBo" }, { "_id" : ObjectId("5b6a5711c2eee4295c63768e"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 20.0, "produce" : "产品2", "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.OrderBo" } ] }
参数解释: form:需要关联的外表名,$lookup的多变查询使用的是左外连接 localField:本表的外表关联字段; foreignField:外表的关联字段; as:参考查询结果,使用$lookup进行查询后会将所有符合条件的文档封装为一个list,as参数定义这个list的名字;
数据处理
使用$unwind将数据打散:
db.user.aggregate([ {$lookup:{from:"orders",localField:"_id",foreignField:"uid",as:"orders"}, {$unwind:"$orders"} ])
$unwind的作用是将文档中的数组拆分为多条,拆分结果为:
/* 1 */ { "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.UserBo", "orders" : { "_id" : ObjectId("5b69062240a6d80a6cece004"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 10.0, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "produce" : "产品1", "_class" : "com.xiangpeng.bo.OrderBo" } } /* 2 */ { "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.UserBo", "orders" : { "_id" : ObjectId("5b6a5711c2eee4295c63768e"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 20.0, "produce" : "产品2", "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.OrderBo" } }
数据过滤
现在可以对数据进行过滤,数据过滤的步骤应该尽可能提前,但如果过滤条件中也需要筛选外表条件的话就没办法放前面了,过滤在聚合中使用$match
db.user.aggregate([ {$lookup:{from:"orders",localField:"_id",foreignField:"uid",as:"orders"}}, {$unwind:"$orders"}, {$match:{name:"小明","orders.produce":"产品2"}} ])
查出小明买的产品2订单
结果展示
/* 1 */ { "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.UserBo", "orders" : { "_id" : ObjectId("5b6a5711c2eee4295c63768e"), "uid" : ObjectId("5b69062240a6d80a6cece003"), "money" : 20.0, "produce" : "产品2", "createtime" : ISODate("2018-08-07T02:38:26.601Z"), "_class" : "com.xiangpeng.bo.OrderBo" } }
如果对字段结果有要求可以使用$project进行字段筛选:
db.user.aggregate([ {$lookup:{from:"orders",localField:"_id",foreignField:"uid",as:"orders"}}, {$unwind:"$orders"}, {$match:{name:"小明","orders.produce":"产品2"}}, {$project:{name:"$name",age:"$age",produce:"$orders.produce",money:"$orders.money"}}])
再聚合中$可以用作引用相应字段的值
结果为:
/* 1 */ { "_id" : ObjectId("5b69062240a6d80a6cece003"), "name" : "小明", "age" : 28, "produce" : "产品2", "money" : 20.0 }
使用spring-data-mongodb在dao层的代码
@Repository("aggregateDao") public class AggregateDaoImpl implements IAggregateDao { @Autowired private MongoTemplate mongoTemplate; public AggregationResults<Document> aggregateLookup() { // 创建条件 AggregationOperation lookup = Aggregation.lookup("orders", "_id", "uid", "orders"); AggregationOperation unwind = Aggregation.unwind("orders"); AggregationOperation match = Aggregation.match(Criteria.where("name").is("小明").and("orders.produce").is("产品2")); AggregationOperation project = Aggregation.project("name", "age", "orders.produce", "orders.money"); // 将条件封装到Aggregate管道 Aggregation aggregation = Aggregation.newAggregation(lookup, unwind, match, project); // 查询 AggregationResults<Document> aggregate = mongoTemplate.aggregate(aggregation, "user", Document.class); return aggregate; } }
ps:一些小坑
1.$lookup是如果涉及关联"_id",注意两个字段的类型,用string类型匹配ObjectId类型是没有结果的~~
2._class字段也是有些作用的,比如说使用$sum时用作分组
3.数据处理后续:Document返回的值,如果用作前端返回,ObjectId是会被当成BSON解析的~
相关文章推荐
- logstash 如何处理 mongodb 导出来的 _id value数据。 how to custom fields of logstash by mongo mapreduce exported data.(example format: {_id:"xxx"} , value:{})
- Spring Batch:将数据从Web服务处理到MongoDB
- Spark 1.6.2 + Beam 2.0.0读取Mongodb数据进行相应逻辑处理
- Node.js + MongoDB + AngularJS - 5 在Node.js中处理数据I0-1
- nodejs读取mongodb返回数据到前台页面[object object]异常处理
- 第6周 处理非结构化数据的利器Mongodb
- 使用mongodb处理上亿级别数据
- mongodb删除已处理过的数据,即非新增数据
- Node.js + MongoDB + AngularJS - 5 在Node.js中处理数据I0-2
- Spark streaming + Kafka 流式数据处理,结果存储至MongoDB、Solr、Neo4j(自用)
- mongodb - 前端form表单传递数据,在保存和取出的数据格式处理函数 - 非递归
- 能源物联网中如何处理上报的大量数据问题的思路分析(题目有点长,但是我不介意它更长)--后续会继续补充
- spark处理mongodb数据(python版)
- mongodb - 前端form表单数据传输,在保存和清除的数据格式的处理程序的 - 非递归
- 能源物联网中如何处理上报的大量数据问题的思路分析(题目有点长,但是我不介意它更长)--后续会继续补充
- 时间序列数据处理的角逐:MongoDB vs. Cassandra
- node.js 读取csv文件数据处理导入mongodb 数据库
- 时间序列数据处理的角逐:MongoDB vs. Cassandra
- [置顶] python结合mongodb处理阿里大数据文件