MongoDB里面有两个Collection,一个是cutting_tool_template(刀具模板),一个是cutting_tool(刀具),每把刀具隶属于一个模板,因此一个模板拥有多把刀具。现在页面需要展示该刀具模板有多少把刀具。

有很多种实现方法:
第一:把刀具集合作为模板的一个列表;

第二:模板增加一个变量(tool_count),增加一把刀具则+1,删除一把刀具则-1;

第三:每次查询模板数据的时候,联合查询刀具表,进行一个mysql里面的count操作。

这里采用了第三种方法。通过cutting_tool.template._id与cutting_tool.template_id进行关联。

MongoDB通过lookup函数来实现两个collection的联合查询。描述如下:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* from: The target collection. 目标集合,即本案例中的[刀具]表
* localField: The local join field. 本地联合变量:即本案例中的[模板表]的ID
* foreignField: The target join field. 目标联合变量,即本案例中的[刀具表]的模板ID
* as: The name for the results. 联合查询后结果的名称
*/
{
from: 'cutting_tool',
localField: '_id',
foreignField: 'template_id',
as: 'tool_array'
}

参考代码一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Test
public void testAggregation( ) {
Query query = new Query();
// 根据刀体类型确定查找的是那种类型的刀具模板,例如铣刀,钻头等刀具类型。
// 这里可以直接用Criteria,会更简洁。但是因为,函数接口是传入query,所以这里用了query做match
query.addCriteria(Criteria.where("type_of_tool_body").is( "Centerdrill" ));
AggregationOperation match = (value) -> new Document("$match", query.getQueryObject() );
AggregationOperation addFields = (AggregationOperationContext aggregationOperationContext) -> {
DBObject dbObject =
new BasicDBObject("tool_count",
new BasicDBObject("$size", "$tool_array"));
return new Document( new BasicDBObject("$addFields", dbObject) );
};
long skipNum = 0L;
int limitNum = 3;
Aggregation aggregation = Aggregation.newAggregation(
match, // 查找特定类型的刀具模板
Aggregation.skip( skipNum ),
Aggregation.limit( limitNum ),
/** 两表联合查询,得到的数据大致是:[{刀具模板一自身数据,tool_array:[属于刀具模板一的所有刀具]}, 刀具模板二...] **/
Aggregation.lookup("cutting_tool", "_id", "template_id", "tool_array"),
/** 针对得到的数据结果进行处理,增加新的变量:tool_count,此时集合为:[{刀具模板一自身数据,tool_array:[属于刀具模板一的所有刀具], tool_count: 值为tool_array的size}, 刀具模板二...] **/
addFields
);

/** 执行聚合查询,因为返回的结果是刀具模板(CuttingToolTemplate),所以,中间变量tool_array不用处理了**/
AggregationResults<CuttingToolTemplate> cutting_tool_template1 = mongoTemplate.aggregate(aggregation,
"cutting_tool_template", CuttingToolTemplate.class);
for ( CuttingToolTemplate ctt : cutting_tool_template1.getMappedResults() ) {
System.out.println("CTT-----------" + ctt );
}
}

参考代码二:实现功能与上述代码一致,只是用另外一种写法来实现。

这种写法更简单,配合MongoDB Compass食用(自动生成Java版的Aggregation代码),更加方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testDoc2Bson( ) {
Query query = new Query();
query.addCriteria(Criteria.where("type_of_tool_body").is( "Centerdrill" ));
Document queryDoc = query.getQueryObject();
int skipNum = 0;
int limitNum = 3;
List<Bson> bsons = new ArrayList<>();
bsons.add( match(queryDoc) );
bsons.add( skip(skipNum) );
bsons.add( limit(limitNum) );
bsons.add( lookup("cutting_tool", "_id", "template_id", "tool_array") );
bsons.add( addFields(new Field("tool_count", new Document("$size", "$tool_array"))) );
/** 因为这里解析获得的是Document,所以把中间变量tool_array排除掉。**/
bsons.add( project(exclude("tool_array")) );

MongoCollection<Document> cutting_tool_template = mongoTemplate.getCollection("cutting_tool_template");
AggregateIterable<Document> aggregate = cutting_tool_template.aggregate(bsons);
for( Document doc : aggregate ){
/** 将Document解析为CuttingToolTemplate对象 **/
CuttingToolTemplate o = mongoTemplate.getConverter().read( CuttingToolTemplate.class, doc);
System.out.println("CTT: " + o);
}
}

简单做下备案,希望对你有用。