赞
踩
普遍使用的{from, localField, foreignField, as}形式的
$lookup只实现了单条件连接表,但是有时候我们会碰到需要多条件连接的情况,其实mongodb在3.6版本之后已经支持了这种操作(详情见这里),但是SpringDataMongo的MongoOperation(MongoTemplate)还没有去适配。这里提供了一个简单的工具类
package vip.starhouse.propertyservicemp.infrastructure.common.db.mongo.custom; import org.springframework.data.mongodb.core.aggregation.AggregationOperation; import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext; import org.bson.Document; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * @author 金艺群 * @description * @date 2021/07/28 **/ public class LookupLetPipelinesOperation implements AggregationOperation { private String jsonOperation; private String from; private String as; private List<String> foreignFields; private List<String> localFields; public LookupLetPipelinesOperation(String jsonOperation) { this.jsonOperation = jsonOperation; } public LookupLetPipelinesOperation() { } @Override public Document toDocument(AggregationOperationContext aggregationOperationContext) { return aggregationOperationContext.getMappedObject(Document.parse(jsonOperation)); } public static LookupLetPipelinesOperation LookupLetPipelinesOperation() { LookupLetPipelinesOperation v = new LookupLetPipelinesOperation("{$lookup: {\n" + " from: '%s', \n" + " let: {%s}, \n" + " pipeline: [\n" + " {$match: {$expr: {$and: [%s]} }} \n" + " ], \n" + " as: '%s'}\n" + "}\n"); v.foreignFields = new ArrayList<>(); v.localFields = new ArrayList<>(); return v; } public LookupLetPipelinesOperation from(String from) { this.from = from; return this; } public LookupLetPipelinesOperation match(String localField, String foreignField) { this.localFields.add(localField); this.foreignFields.add(foreignField); return this; } public LookupLetPipelinesOperation as(String as) { this.as = as; return this; } public LookupLetPipelinesOperation build() { String foreignFieldsIntegral = generateForeignFieldsIntegral(); String matchPairs = generateMatchPairs(); this.jsonOperation = String.format(this.jsonOperation, from, foreignFieldsIntegral, matchPairs, as); return this; } private String generateForeignFieldsIntegral() { StringBuilder sb = new StringBuilder(); this.foreignFields.forEach(f -> { sb.append(f); sb.append(":"); sb.append("'$"); sb.append(f); sb.append("'"); sb.append(","); }); return sb.deleteCharAt(sb.length() - 1).toString(); } private String generateMatchPairs() { StringBuilder sb = new StringBuilder(); Iterator<String> localIte = this.localFields.iterator(); Iterator<String> foreignIte = this.foreignFields.iterator(); while (localIte.hasNext()) { String l = localIte.next(); String f = foreignIte.next(); sb.append("{$eq: ['$"); sb.append(l); sb.append("',"); sb.append("'$$"); sb.append(f); sb.append("']}"); sb.append(","); } return sb.deleteCharAt(sb.length() - 1).toString(); } }

LookupLetPipelinesOperation letPipelineLookup = LookupLetPipelinesOperation.LookupLetPipelinesOperation() .from("message") .match("from", "from") .match("to", "to") .as("ms") .build(); FacetOperation facets = Aggregation.facet() (..........略); Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(Criteria.where("_id").is(new ObjectId(messageId))), Aggregation.limit(1), // 获取 MessageId对应的from&to,根据这两个id进行多条件连接 // 多条件连接 letPipelineLookup, Aggregation.unwind("ms"), Aggregation.project() .and("ms._id").as("_id") .and("ms.from").as("from") .and("ms.to").as("to") .and("ms.content").as("content") .and("ms.property_id").as("property_id") .and("ms.created_at").as("created_at") .and("ms.updated_at").as("updated_at"), facets, Aggregation.unwind("introduction"), Aggregation.addFields().addField("introduction").withValue("$introduction.share_title").build() ); List<MessageListVO> resultList = mongo.aggregate(aggregation, "message", MessageListVO.class).getMappedResults();
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。