|
20 | 20 | import java.util.Collection; |
21 | 21 | import java.util.Collections; |
22 | 22 | import java.util.List; |
| 23 | +import java.util.stream.Collectors; |
23 | 24 |
|
24 | 25 | import org.bson.Document; |
25 | 26 |
|
@@ -177,6 +178,48 @@ public ProjectionOperation andInclude(Fields fields) { |
177 | 178 | return new ProjectionOperation(this.projections, FieldProjection.from(fields, true)); |
178 | 179 | } |
179 | 180 |
|
| 181 | + /** |
| 182 | + * Includes the current {@link ProjectionOperation} as an array with given name. <br /> |
| 183 | + * If you want to specify array values directly use {@link #andArrayOf(Object...)}. |
| 184 | + * |
| 185 | + * @param name the target property name. |
| 186 | + * @return new instance of {@link ProjectionOperation}. |
| 187 | + * @since 2.2 |
| 188 | + */ |
| 189 | + public ProjectionOperation asArray(String name) { |
| 190 | + |
| 191 | + return new ProjectionOperation(Collections.emptyList(), |
| 192 | + Collections.singletonList(new ArrayProjection(Fields.field(name), (List) this.projections))); |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * Includes the given values ({@link Field field references}, {@link AggregationExpression expression}, plain values) |
| 197 | + * as an array. <br /> |
| 198 | + * The target property name needs to be set via {@link ArrayProjectionOperationBuilder#as(String)}. |
| 199 | + * |
| 200 | + * @param values must not be {@literal null}. |
| 201 | + * @return new instance of {@link ArrayProjectionOperationBuilder}. |
| 202 | + * @throws IllegalArgumentException if the required argument it {@literal null}. |
| 203 | + * @since 2.2 |
| 204 | + */ |
| 205 | + public ArrayProjectionOperationBuilder andArrayOf(Object... values) { |
| 206 | + |
| 207 | + ArrayProjectionOperationBuilder builder = new ArrayProjectionOperationBuilder(this); |
| 208 | + |
| 209 | + for (Object value : values) { |
| 210 | + |
| 211 | + if (value instanceof Field) { |
| 212 | + builder.and((Field) value); |
| 213 | + } else if (value instanceof AggregationExpression) { |
| 214 | + builder.and((AggregationExpression) value); |
| 215 | + } else { |
| 216 | + builder.and(value); |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + return builder; |
| 221 | + } |
| 222 | + |
180 | 223 | /* |
181 | 224 | * (non-Javadoc) |
182 | 225 | * @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields() |
@@ -1743,4 +1786,95 @@ public Document toDocument(AggregationOperationContext context) { |
1743 | 1786 | return context.getMappedObject(projections, type); |
1744 | 1787 | } |
1745 | 1788 | } |
| 1789 | + |
| 1790 | + /** |
| 1791 | + * @author Christoph Strobl |
| 1792 | + * @since 2.2 |
| 1793 | + */ |
| 1794 | + public static class ArrayProjectionOperationBuilder { |
| 1795 | + |
| 1796 | + private ProjectionOperation target; |
| 1797 | + private final List<Object> projections; |
| 1798 | + |
| 1799 | + public ArrayProjectionOperationBuilder(ProjectionOperation target) { |
| 1800 | + |
| 1801 | + this.target = target; |
| 1802 | + this.projections = new ArrayList<>(); |
| 1803 | + } |
| 1804 | + |
| 1805 | + public ArrayProjectionOperationBuilder and(AggregationExpression expression) { |
| 1806 | + |
| 1807 | + this.projections.add(expression); |
| 1808 | + return this; |
| 1809 | + } |
| 1810 | + |
| 1811 | + public ArrayProjectionOperationBuilder and(Field field) { |
| 1812 | + |
| 1813 | + this.projections.add(field); |
| 1814 | + return this; |
| 1815 | + } |
| 1816 | + |
| 1817 | + public ArrayProjectionOperationBuilder and(Object value) { |
| 1818 | + |
| 1819 | + this.projections.add(value); |
| 1820 | + return this; |
| 1821 | + } |
| 1822 | + |
| 1823 | + /** |
| 1824 | + * Create the {@link ProjectionOperation} for the array property with given {@literal name}. |
| 1825 | + * |
| 1826 | + * @param name The target property name. Must not be {@literal null}. |
| 1827 | + * @return new instance of {@link ArrayProjectionOperationBuilder}. |
| 1828 | + */ |
| 1829 | + public ProjectionOperation as(String name) { |
| 1830 | + |
| 1831 | + return new ProjectionOperation(target.projections, |
| 1832 | + Collections.singletonList(new ArrayProjection(Fields.field(name), this.projections))); |
| 1833 | + } |
| 1834 | + } |
| 1835 | + |
| 1836 | + /** |
| 1837 | + * @author Christoph Strobl |
| 1838 | + * @since 2.2 |
| 1839 | + */ |
| 1840 | + static class ArrayProjection extends Projection { |
| 1841 | + |
| 1842 | + private final Field targetField; |
| 1843 | + private final List<Object> projections; |
| 1844 | + |
| 1845 | + public ArrayProjection(Field targetField, List<Object> projections) { |
| 1846 | + |
| 1847 | + super(targetField); |
| 1848 | + this.targetField = targetField; |
| 1849 | + this.projections = projections; |
| 1850 | + } |
| 1851 | + |
| 1852 | + @Override |
| 1853 | + public Document toDocument(AggregationOperationContext context) { |
| 1854 | + |
| 1855 | + return new Document(targetField.getName(), |
| 1856 | + projections.stream().map(it -> toArrayEntry(it, context)).collect(Collectors.toList())); |
| 1857 | + } |
| 1858 | + |
| 1859 | + private Object toArrayEntry(Object projection, AggregationOperationContext ctx) { |
| 1860 | + |
| 1861 | + if (projection instanceof Field) { |
| 1862 | + return ctx.getReference((Field) projection).toString(); |
| 1863 | + } |
| 1864 | + |
| 1865 | + if (projection instanceof AggregationExpression) { |
| 1866 | + return ((AggregationExpression) projection).toDocument(ctx); |
| 1867 | + } |
| 1868 | + |
| 1869 | + if (projection instanceof FieldProjection) { |
| 1870 | + return ctx.getReference(((FieldProjection) projection).getExposedField().getTarget()).toString(); |
| 1871 | + } |
| 1872 | + |
| 1873 | + if (projection instanceof Projection) { |
| 1874 | + ((Projection) projection).toDocument(ctx); |
| 1875 | + } |
| 1876 | + |
| 1877 | + return projection; |
| 1878 | + } |
| 1879 | + } |
1746 | 1880 | } |
0 commit comments