#523 - Add example for declarative MongoDB aggregations.
Original pull request: #526. closes: #523
This commit is contained in:
committed by
Mark Paluch
parent
a44f93a9bc
commit
84ca79d97f
53
mongodb/aggregation/README.md
Normal file
53
mongodb/aggregation/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Spring Data MongoDB - Aggregations
|
||||
|
||||
This project contains usage samples for using MongoDB [Aggregations](https://docs.mongodb.com/manual/aggregation/)
|
||||
showing both the programmatic and declarative approach for integrating an Aggregation Pipeline into the repository lay.
|
||||
|
||||
## Programmatic
|
||||
|
||||
The programmatic approach uses a [custom repository](https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.custom-implementations) implementation along with the [Aggregation Framework](https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation).
|
||||
|
||||
```java
|
||||
class OrderRepositoryImpl implements OrderRepositoryCustom {
|
||||
|
||||
private MongoOperations operations;
|
||||
|
||||
// ...
|
||||
|
||||
@Override
|
||||
public Invoice getInvoiceFor(Order order) {
|
||||
|
||||
AggregationResults<Invoice> results = operations.aggregate(newAggregation(Order.class,
|
||||
match(where("id").is(order.getId())),
|
||||
unwind("items"),
|
||||
project("id", "customerId", "items")
|
||||
.andExpression("'$items.price' * '$items.quantity'").as("lineTotal"),
|
||||
group("id")
|
||||
.sum("lineTotal").as("netAmount")
|
||||
.addToSet("items").as("items"),
|
||||
project("id", "items", "netAmount")
|
||||
.and("orderId").previousOperation()
|
||||
.andExpression("netAmount * [0]", taxRate).as("taxAmount")
|
||||
.andExpression("netAmount * (1 + [0])", taxRate).as("totalAmount")
|
||||
), Invoice.class);
|
||||
|
||||
return results.getUniqueMappedResult();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Declarative
|
||||
|
||||
The [declarative approach](https://docs.spring.io/spring-data/mongodb/docs/2.2.0.RC2/reference/html/#mongodb.repositories.queries.aggregation) allows to define an Aggregation Pipeline via the `@Aggregation` annotation.
|
||||
|
||||
```java
|
||||
public interface OrderRepository extends CrudRepository<Order, String>, OrderRepositoryCustom {
|
||||
|
||||
@Aggregation("{ $group : { _id : $customerId, total : { $sum : 1 } } }")
|
||||
List<OrdersPerCustomer> totalOrdersPerCustomer(Sort sort);
|
||||
|
||||
@Aggregation(pipeline = { "{ $match : { customerId : ?0 } }", "{ $count : total }" })
|
||||
Long totalOrdersForCustomer(String customerId);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package example.springdata.mongodb.aggregation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.repository.Aggregation;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
@@ -22,7 +26,13 @@ import org.springframework.data.repository.CrudRepository;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface OrderRepository extends CrudRepository<Order, String>, OrderRepositoryCustom {
|
||||
|
||||
@Aggregation("{ $group : { _id : $customerId, total : { $sum : 1 } } }")
|
||||
List<OrdersPerCustomer> totalOrdersPerCustomer(Sort sort);
|
||||
|
||||
@Aggregation(pipeline = { "{ $match : { customerId : ?0 } }", "{ $count : total }" })
|
||||
Long totalOrdersForCustomer(String customerId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package example.springdata.mongodb.aggregation;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Value
|
||||
public class OrdersPerCustomer {
|
||||
|
||||
@Id //
|
||||
private String customerId;
|
||||
private Long total;
|
||||
}
|
||||
@@ -21,11 +21,13 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
@@ -33,6 +35,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@@ -64,4 +67,33 @@ public class OrderRepositoryIntegrationTests {
|
||||
assertThat(invoice.getTaxAmount(), is(closeTo(1.577, 000001)));
|
||||
assertThat(invoice.getTotalAmount(), is(closeTo(9.877, 000001)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void declarativeAggregationWithSort() {
|
||||
|
||||
repository.save(new Order("c42", new Date()).addItem(product1));
|
||||
repository.save(new Order("c42", new Date()).addItem(product2));
|
||||
repository.save(new Order("c42", new Date()).addItem(product3));
|
||||
|
||||
repository.save(new Order("b12", new Date()).addItem(product1));
|
||||
repository.save(new Order("b12", new Date()).addItem(product1));
|
||||
|
||||
Assertions.assertThat(repository.totalOrdersPerCustomer(Sort.by(Sort.Order.desc("total")))) //
|
||||
.containsExactly( //
|
||||
new OrdersPerCustomer("c42", 3L), new OrdersPerCustomer("b12", 2L) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiStageDeclarativeAggregation() {
|
||||
|
||||
repository.save(new Order("c42", new Date()).addItem(product1));
|
||||
repository.save(new Order("c42", new Date()).addItem(product2));
|
||||
repository.save(new Order("c42", new Date()).addItem(product3));
|
||||
|
||||
repository.save(new Order("b12", new Date()).addItem(product1));
|
||||
repository.save(new Order("b12", new Date()).addItem(product1));
|
||||
|
||||
Assertions.assertThat(repository.totalOrdersForCustomer("c42")).isEqualTo(3);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user