|
|
|
@ -15,6 +15,8 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
package org.springframework.data.mongodb.core.aggregation; |
|
|
|
package org.springframework.data.mongodb.core.aggregation; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
import org.bson.Document; |
|
|
|
import org.bson.Document; |
|
|
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField; |
|
|
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField; |
|
|
|
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation; |
|
|
|
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation; |
|
|
|
@ -28,6 +30,7 @@ import org.springframework.util.Assert; |
|
|
|
* @author Alessio Fachechi |
|
|
|
* @author Alessio Fachechi |
|
|
|
* @author Christoph Strobl |
|
|
|
* @author Christoph Strobl |
|
|
|
* @author Mark Paluch |
|
|
|
* @author Mark Paluch |
|
|
|
|
|
|
|
* @author Sangyong Choi |
|
|
|
* @since 1.9 |
|
|
|
* @since 1.9 |
|
|
|
* @see <a href="https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/">MongoDB Aggregation Framework: |
|
|
|
* @see <a href="https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/">MongoDB Aggregation Framework: |
|
|
|
* $lookup</a> |
|
|
|
* $lookup</a> |
|
|
|
@ -39,6 +42,11 @@ public class LookupOperation implements FieldsExposingAggregationOperation, Inhe |
|
|
|
private final Field foreignField; |
|
|
|
private final Field foreignField; |
|
|
|
private final ExposedField as; |
|
|
|
private final ExposedField as; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
|
|
|
private final Let let; |
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
|
|
|
private final AggregationPipeline pipeline; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a new {@link LookupOperation} for the given {@link Field}s. |
|
|
|
* Creates a new {@link LookupOperation} for the given {@link Field}s. |
|
|
|
* |
|
|
|
* |
|
|
|
@ -48,7 +56,10 @@ public class LookupOperation implements FieldsExposingAggregationOperation, Inhe |
|
|
|
* @param as must not be {@literal null}. |
|
|
|
* @param as must not be {@literal null}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public LookupOperation(Field from, Field localField, Field foreignField, Field as) { |
|
|
|
public LookupOperation(Field from, Field localField, Field foreignField, Field as) { |
|
|
|
|
|
|
|
this(from, localField, foreignField, as, null, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public LookupOperation(Field from, Field localField, Field foreignField, Field as, @Nullable Let let, @Nullable AggregationPipeline pipeline) { |
|
|
|
Assert.notNull(from, "From must not be null"); |
|
|
|
Assert.notNull(from, "From must not be null"); |
|
|
|
Assert.notNull(localField, "LocalField must not be null"); |
|
|
|
Assert.notNull(localField, "LocalField must not be null"); |
|
|
|
Assert.notNull(foreignField, "ForeignField must not be null"); |
|
|
|
Assert.notNull(foreignField, "ForeignField must not be null"); |
|
|
|
@ -58,6 +69,8 @@ public class LookupOperation implements FieldsExposingAggregationOperation, Inhe |
|
|
|
this.localField = localField; |
|
|
|
this.localField = localField; |
|
|
|
this.foreignField = foreignField; |
|
|
|
this.foreignField = foreignField; |
|
|
|
this.as = new ExposedField(as, true); |
|
|
|
this.as = new ExposedField(as, true); |
|
|
|
|
|
|
|
this.let = let; |
|
|
|
|
|
|
|
this.pipeline = pipeline; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@ -75,6 +88,14 @@ public class LookupOperation implements FieldsExposingAggregationOperation, Inhe |
|
|
|
lookupObject.append("foreignField", foreignField.getTarget()); |
|
|
|
lookupObject.append("foreignField", foreignField.getTarget()); |
|
|
|
lookupObject.append("as", as.getTarget()); |
|
|
|
lookupObject.append("as", as.getTarget()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (let != null) { |
|
|
|
|
|
|
|
lookupObject.append("let", let.toDocument(context)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pipeline != null) { |
|
|
|
|
|
|
|
lookupObject.append("pipeline", pipeline.toDocuments(context)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return new Document(getOperator(), lookupObject); |
|
|
|
return new Document(getOperator(), lookupObject); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -184,4 +205,49 @@ public class LookupOperation implements FieldsExposingAggregationOperation, Inhe |
|
|
|
return this; |
|
|
|
return this; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static class Let implements AggregationExpression{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final List<ExpressionVariable> vars; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Let(List<ExpressionVariable> vars) { |
|
|
|
|
|
|
|
Assert.notEmpty(vars, "'let' must not be null or empty"); |
|
|
|
|
|
|
|
this.vars = vars; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Document toDocument(AggregationOperationContext context) { |
|
|
|
|
|
|
|
return toLet(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Document toLet() { |
|
|
|
|
|
|
|
Document mappedVars = new Document(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (ExpressionVariable var : this.vars) { |
|
|
|
|
|
|
|
mappedVars.putAll(getMappedVariable(var)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mappedVars; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Document getMappedVariable(ExpressionVariable var) { |
|
|
|
|
|
|
|
return new Document(var.variableName, prefixDollarSign(var.expression)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String prefixDollarSign(String expression) { |
|
|
|
|
|
|
|
return "$" + expression; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static class ExpressionVariable { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final String variableName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final String expression; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ExpressionVariable(String variableName, String expression) { |
|
|
|
|
|
|
|
this.variableName = variableName; |
|
|
|
|
|
|
|
this.expression = expression; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|