参考:
- 详解MongoDB中的多表关联查询($lookup)
- Java实现对mongoDB的两表关联查询
聚合框架
聚合框架是MongoDB的高级查询语言,它允许我们通过转换和合并多个文档中的数据来生成新的单个文档中不存在的信息。
聚合管道操作主要包含下面几个部分:
| 命令 | 功能描述 |
| $project | 指定输出文档里的字段. |
| $match | 选择要处理的文档,与fine()类似。 |
| $limit | 限制传递给下一步的文档数量。 |
| $skip | 跳过一定数量的文档。 |
| $unwind | 扩展数组,为每个数组入口生成一个输出文档。 |
| $group | 根据key来分组文档。 |
| $sort | 排序文档。 |
| $geoNear | 选择某个地理位置附近的的文档。 |
| $out | 把管道的结果写入某个集合。 |
| $redact | 控制特定数据的访问。 |
$lookup |
多表关联(3.2版本新增) |
MongoDB查询(工具:Robo 3T):
// 两个集合关联查询
// 小表(HTQH_BROKER_CUST_RELA)做主表
db.getCollection('HTQH_BROKER_CUST_RELA').aggregate([ // 主表的查询条件{$match: {'BROKER_NUM': {$in: ['DA1831']}}},{$lookup: {// 大表(D01_CUST_LABEL)做子表from: 'D01_CUST_LABEL', localField: 'CUST_NUM', // 主表字段foreignField: 'CUST_NUM', // 子表字段as: 'BROKER_CUST' // 别名}}, // 关联后的查询条件{$match: {// 查询满足条件(LABL_GRP='sex_cd',且LABL_ID in ['1', '2'])或条件(LABL_GRP='cust_type_cd',且LABL_ID in ['100', '102'])的所有数据$or: [// 查询从表数据,需要用别名.从表的字段名{$and: [{'BROKER_CUST.LABL_GRP': 'sex_cd', 'BROKER_CUST.LABL_ID': {$in: ['1', '2']}}]}, {$and: [{'BROKER_CUST.LABL_GRP': 'cust_type_cd', 'BROKER_CUST.LABL_ID': {$in: ['100', '102']}}]}]}},// 查询结果只显示CUST_NUM列,_id需手动隐藏
// {$project: {CUST_NUM: 1, _id: 0}}, // 统计总条数{$group: {_id: 'Total', count: {$sum: 1}}}, // 按CUST_NUM分组,并统计每个CUST_NUM出现的次数
// {$group: {_id: '$CUST_NUM', count: {$sum: 1}}},
]);
Java:
<dependency><groupId>org.mongodb</groupId><artifactId>mongodb-driver</artifactId><version>3.2.2</version>
</dependency>
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.3.1</version>
</dependency>
<!-- 因为是jdk1.6所以用的低版本的jar -->
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-mongodb</artifactId><version>1.5.4.RELEASE</version>
</dependency>
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;public class demo {// DataRow是一个HashMap,入参都是查询条件private List<String> queryCustNum(String broker_nums, String labl_thme_id, String labl_grp_clas_id, String labl_grp, String[] label_id, List<String> custNums) throws TKMongoException {long beginTime = System.currentTimeMillis();TKMongoClient tkMongoClient = new TKMongoClient();// 联合查询条件List<Bson> aggregationList = new LinkedList<Bson>();// 主表查询条件String[] brokerNumsArray = broker_nums.replaceAll("'", "").replaceAll(" ", "").split(",");aggregationList.add(Aggregates.match(Filters.in("BROKER_NUM", brokerNumsArray)));// 从表名、主表连接字段、从表连接字段、别名aggregationList.add(Aggregates.lookup(CacheConstants.DOCUMENT_NAME, "CUST_NUM", "CUST_NUM", "BROKER_CUST")); // 从表查询条件aggregationList.add(Aggregates.match(Filters.and(Filters.eq("BROKER_CUST.LABL_THME_ID", labl_thme_id), Filters.eq("BROKER_CUST.LABL_GRP_CLAS_ID", labl_grp_clas_id), Filters.eq("BROKER_CUST.LABL_GRP", labl_grp), Filters.in("BROKER_CUST.LABL_ID", label_id) )));if (custNums != null && custNums.size() != 0) {aggregationList.add(Aggregates.match(Filters.and(Filters.in("BROKER_CUST.CUST_NUM", custNums.toArray()))));}BasicDBObject basicDBObject = new BasicDBObject();basicDBObject.put("CUST_NUM", true);basicDBObject.put("_id", false);aggregationList.add(Aggregates.project(basicDBObject)); // 从第0条开始查,查50条记录
// aggregationList.add(Aggregates.skip(0));
// aggregationList.add(Aggregates.limit(50));List<DataRow> labelList = tkMongoClient.aggregate(CacheConstants.HTQH_BROKER_CUST_RELA, aggregationList);if (labelList != null && labelList.size() != 0) {logger.info("size={}", labelList.size());}long endTime = System.currentTimeMillis();logger.info("耗时:{}ms", endTime - beginTime);// 打包出参List<String> resultList = new LinkedList<String>();for (DataRow dr : labelList) {if (resultList.contains(dr.getString("CUST_NUM"))) {continue;}resultList.add(dr.getString("CUST_NUM"));}return resultList;}
}