39
39
*/
40
40
public class LookupOperation implements FieldsExposingAggregationOperation , InheritsFieldsAggregationOperation {
41
41
42
- private final String from ;
42
+ private Object from ;
43
43
44
44
@ Nullable //
45
45
private final Field localField ;
@@ -97,6 +97,22 @@ public LookupOperation(String from, @Nullable Let let, AggregationPipeline pipel
97
97
*/
98
98
public LookupOperation (String from , @ Nullable Field localField , @ Nullable Field foreignField , @ Nullable Let let ,
99
99
@ Nullable AggregationPipeline pipeline , Field as ) {
100
+ this ((Object ) from , localField , foreignField , let , pipeline , as );
101
+ }
102
+
103
+ /**
104
+ * Creates a new {@link LookupOperation} for the given combination of {@link Field}s and {@link AggregationPipeline
105
+ * pipeline}.
106
+ *
107
+ * @param from must not be {@literal null}. Can be eiter the target collection name or a {@link Class}.
108
+ * @param localField can be {@literal null} if {@literal pipeline} is present.
109
+ * @param foreignField can be {@literal null} if {@literal pipeline} is present.
110
+ * @param let can be {@literal null} if {@literal localField} and {@literal foreignField} are present.
111
+ * @param as must not be {@literal null}.
112
+ * @since 4.1
113
+ */
114
+ private LookupOperation (Object from , @ Nullable Field localField , @ Nullable Field foreignField , @ Nullable Let let ,
115
+ @ Nullable AggregationPipeline pipeline , Field as ) {
100
116
101
117
Assert .notNull (from , "From must not be null" );
102
118
if (pipeline == null ) {
@@ -125,12 +141,14 @@ public Document toDocument(AggregationOperationContext context) {
125
141
126
142
Document lookupObject = new Document ();
127
143
128
- lookupObject .append ("from" , from );
144
+ lookupObject .append ("from" , getCollectionName (context ));
145
+
129
146
if (localField != null ) {
130
147
lookupObject .append ("localField" , localField .getTarget ());
131
148
}
149
+
132
150
if (foreignField != null ) {
133
- lookupObject .append ("foreignField" , foreignField . getTarget ( ));
151
+ lookupObject .append ("foreignField" , getForeignFieldName ( context ));
134
152
}
135
153
if (let != null ) {
136
154
lookupObject .append ("let" , let .toDocument (context ).get ("$let" , Document .class ).get ("vars" ));
@@ -144,6 +162,16 @@ public Document toDocument(AggregationOperationContext context) {
144
162
return new Document (getOperator (), lookupObject );
145
163
}
146
164
165
+ String getCollectionName (AggregationOperationContext context ) {
166
+ return from instanceof Class <?> type ? context .getCollection (type ) : from .toString ();
167
+ }
168
+
169
+ String getForeignFieldName (AggregationOperationContext context ) {
170
+
171
+ return from instanceof Class <?> type ? context .getMappedFieldName (type , foreignField .getTarget ())
172
+ : foreignField .getTarget ();
173
+ }
174
+
147
175
@ Override
148
176
public String getOperator () {
149
177
return "$lookup" ;
@@ -158,16 +186,28 @@ public static FromBuilder newLookup() {
158
186
return new LookupOperationBuilder ();
159
187
}
160
188
161
- public static interface FromBuilder {
189
+ public interface FromBuilder {
162
190
163
191
/**
164
192
* @param name the collection in the same database to perform the join with, must not be {@literal null} or empty.
165
193
* @return never {@literal null}.
166
194
*/
167
195
LocalFieldBuilder from (String name );
196
+
197
+ /**
198
+ * Use the given type to determine name of the foreign collection and map
199
+ * {@link ForeignFieldBuilder#foreignField(String)} against it to consider eventually present
200
+ * {@link org.springframework.data.mongodb.core.mapping.Field} annotations.
201
+ *
202
+ * @param type the type of the target collection in the same database to perform the join with, must not be
203
+ * {@literal null}.
204
+ * @return never {@literal null}.
205
+ * @since 4.2
206
+ */
207
+ LocalFieldBuilder from (Class <?> type );
168
208
}
169
209
170
- public static interface LocalFieldBuilder extends PipelineBuilder {
210
+ public interface LocalFieldBuilder extends PipelineBuilder {
171
211
172
212
/**
173
213
* @param name the field from the documents input to the {@code $lookup} stage, must not be {@literal null} or
@@ -177,7 +217,7 @@ public static interface LocalFieldBuilder extends PipelineBuilder {
177
217
ForeignFieldBuilder localField (String name );
178
218
}
179
219
180
- public static interface ForeignFieldBuilder {
220
+ public interface ForeignFieldBuilder {
181
221
182
222
/**
183
223
* @param name the field from the documents in the {@code from} collection, must not be {@literal null} or empty.
@@ -246,7 +286,7 @@ default AsBuilder pipeline(AggregationOperation... stages) {
246
286
LookupOperation as (String name );
247
287
}
248
288
249
- public static interface AsBuilder extends PipelineBuilder {
289
+ public interface AsBuilder extends PipelineBuilder {
250
290
251
291
/**
252
292
* @param name the name of the new array field to add to the input documents, must not be {@literal null} or empty.
@@ -264,7 +304,7 @@ public static interface AsBuilder extends PipelineBuilder {
264
304
public static final class LookupOperationBuilder
265
305
implements FromBuilder , LocalFieldBuilder , ForeignFieldBuilder , AsBuilder {
266
306
267
- private @ Nullable String from ;
307
+ private @ Nullable Object from ;
268
308
private @ Nullable Field localField ;
269
309
private @ Nullable Field foreignField ;
270
310
private @ Nullable ExposedField as ;
@@ -288,6 +328,14 @@ public LocalFieldBuilder from(String name) {
288
328
return this ;
289
329
}
290
330
331
+ @ Override
332
+ public LocalFieldBuilder from (Class <?> type ) {
333
+
334
+ Assert .notNull (type , "'From' must not be null" );
335
+ from = type ;
336
+ return this ;
337
+ }
338
+
291
339
@ Override
292
340
public AsBuilder foreignField (String name ) {
293
341
0 commit comments