4444public class ProjectionOperation implements FieldsExposingAggregationOperation {
4545
4646 private static final List <Projection > NONE = Collections .emptyList ();
47+ private static final String EXCLUSION_ERROR = "Exclusion of field %s not allowed. Projections by the mongodb "
48+ + "aggregation framework only support the exclusion of the %s field!" ;
4749
4850 private final List <Projection > projections ;
4951
@@ -60,7 +62,7 @@ public ProjectionOperation() {
6062 * @param fields must not be {@literal null}.
6163 */
6264 public ProjectionOperation (Fields fields ) {
63- this (NONE , ProjectionOperationBuilder .FieldProjection .from (fields , true ));
65+ this (NONE , ProjectionOperationBuilder .FieldProjection .from (fields ));
6466 }
6567
6668 /**
@@ -117,23 +119,29 @@ public ProjectionOperationBuilder and(String name) {
117119 /**
118120 * Excludes the given fields from the projection.
119121 *
120- * @param fields must not be {@literal null}.
122+ * @param fieldNames must not be {@literal null}.
121123 * @return
122124 */
123- public ProjectionOperation andExclude (String ... fields ) {
124- List <FieldProjection > excludeProjections = FieldProjection .from (Fields .fields (fields ), false );
125+ public ProjectionOperation andExclude (String ... fieldNames ) {
126+
127+ for (String fieldName : fieldNames ) {
128+ Assert .isTrue (Fields .UNDERSCORE_ID .equals (fieldName ),
129+ String .format (EXCLUSION_ERROR , fieldName , Fields .UNDERSCORE_ID ));
130+ }
131+
132+ List <FieldProjection > excludeProjections = FieldProjection .from (Fields .fields (fieldNames ), false );
125133 return new ProjectionOperation (this .projections , excludeProjections );
126134 }
127135
128136 /**
129137 * Includes the given fields into the projection.
130138 *
131- * @param fields must not be {@literal null}.
139+ * @param fieldNames must not be {@literal null}.
132140 * @return
133141 */
134- public ProjectionOperation andInclude (String ... fields ) {
142+ public ProjectionOperation andInclude (String ... fieldNames ) {
135143
136- List <FieldProjection > projections = FieldProjection .from (Fields .fields (fields ), true );
144+ List <FieldProjection > projections = FieldProjection .from (Fields .fields (fieldNames ), true );
137145 return new ProjectionOperation (this .projections , projections );
138146 }
139147
@@ -387,31 +395,31 @@ private FieldProjection(Field field, Object value) {
387395 this .value = value ;
388396 }
389397
398+ /**
399+ * Factory method to easily create {@link FieldProjection}s for the given {@link Fields}. Fields are projected as
400+ * references with their given name. A field {@code foo} will be projected as: {@code foo : 1 } .
401+ *
402+ * @param fields the {@link Fields} to in- or exclude, must not be {@literal null}.
403+ * @return
404+ */
405+ public static List <? extends Projection > from (Fields fields ) {
406+ return from (fields , null );
407+ }
408+
390409 /**
391410 * Factory method to easily create {@link FieldProjection}s for the given {@link Fields}.
392411 *
393412 * @param fields the {@link Fields} to in- or exclude, must not be {@literal null}.
394- * @param include whether to include or exclude the fields .
413+ * @param value to use for the given field .
395414 * @return
396415 */
397- public static List <FieldProjection > from (Fields fields , boolean include ) {
416+ public static List <FieldProjection > from (Fields fields , Object value ) {
398417
399418 Assert .notNull (fields , "Fields must not be null!" );
400419 List <FieldProjection > projections = new ArrayList <FieldProjection >();
401420
402421 for (Field field : fields ) {
403-
404- if (!include ) {
405- if (!Fields .UNDERSCORE_ID .equals (field .getName ())) {
406- throw new IllegalArgumentException (
407- String
408- .format (
409- "Exclusion of field %s not allowed. Projections by the mongodb aggregation framework only support the exclusion of the %s field!" ,
410- field .getName (), Fields .UNDERSCORE_ID ));
411- }
412- }
413-
414- projections .add (new FieldProjection (field , include ? null : 0 ));
422+ projections .add (new FieldProjection (field , value ));
415423 }
416424
417425 return projections ;
@@ -423,13 +431,32 @@ public static List<FieldProjection> from(Fields fields, boolean include) {
423431 */
424432 @ Override
425433 public DBObject toDBObject (AggregationOperationContext context ) {
434+ return new BasicDBObject (field .getName (), renderFieldValue (context ));
435+ }
436+
437+ private Object renderFieldValue (AggregationOperationContext context ) {
438+
439+ // implicit reference or explicit include?
440+ if (value == null || Boolean .TRUE .equals (value )) {
441+
442+ // check whether referenced field exists in the context
443+ FieldReference reference = context .getReference (field .getTarget ());
444+
445+ if (field .getName ().equals (field .getTarget ())) {
446+
447+ // render field as included
448+ return 1 ;
449+ }
450+
451+ // render field reference
452+ return reference .toString ();
453+ } else if (Boolean .FALSE .equals (value )) {
426454
427- if ( value != null ) {
428- return new BasicDBObject ( field . getName (), value ) ;
455+ // render field as excluded
456+ return 0 ;
429457 }
430458
431- FieldReference reference = context .getReference (field .getTarget ());
432- return new BasicDBObject (field .getName (), reference .toString ());
459+ return value ;
433460 }
434461 }
435462
0 commit comments