BAEL 575: Pull request for Projections and Aggregation in Spring Data MongoDB (#1047)
* BAEL-575 - update spring data mongodb version to 1.9.6, update query dsl version to 4.1.4, Add constuctor to user class, add projection tests * BAEL-575 - Add aggregation test files and zips.json resource
This commit is contained in:
parent
af44518a6a
commit
6f9e6e0f20
|
@ -75,12 +75,12 @@
|
|||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-mongodb</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
</dependency>
|
||||
|
@ -167,12 +167,12 @@
|
|||
|
||||
<org.springframework.version>4.3.4.RELEASE</org.springframework.version>
|
||||
|
||||
<org.springframework.data.version>1.8.6.RELEASE</org.springframework.data.version>
|
||||
<org.springframework.data.version>1.9.6.RELEASE</org.springframework.data.version>
|
||||
|
||||
<org.hamcrest.version>1.3</org.hamcrest.version>
|
||||
<junit.version>4.12</junit.version>
|
||||
<rest-assured.version>2.9.0</rest-assured.version>
|
||||
<querydsl.version>3.7.4</querydsl.version>
|
||||
<querydsl.version>4.1.4</querydsl.version>
|
||||
<mysema.maven.version>1.1.3</mysema.maven.version>
|
||||
|
||||
<org.slf4j.version>1.7.21</org.slf4j.version>
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.springframework.data.mongodb.core.mapping.DBRef;
|
|||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
|
||||
import com.mysema.query.annotations.QueryEntity;
|
||||
import com.querydsl.core.annotations.QueryEntity;
|
||||
|
||||
@QueryEntity
|
||||
@Document
|
||||
|
@ -37,6 +37,11 @@ public class User {
|
|||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String name, Integer age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@PersistenceConstructor
|
||||
public User(final String name, @Value("#root.age ?: 0") final Integer age, final EmailAddress emailAddress) {
|
||||
|
|
|
@ -26,4 +26,10 @@ public interface UserRepository extends MongoRepository<User, String>, QueryDslP
|
|||
List<User> findByNameStartingWith(String regexp);
|
||||
|
||||
List<User> findByNameEndingWith(String regexp);
|
||||
|
||||
@Query(value="{}", fields="{name : 1}")
|
||||
List<User> findNameAndId();
|
||||
|
||||
@Query(value="{}", fields="{_id : 0}")
|
||||
List<User> findNameAndAgeExcludeId();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package org.baeldung.aggregation;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.baeldung.aggregation.model.StatePopulation;
|
||||
import org.baeldung.config.MongoConfig;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.LimitOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.SortOperation;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MongoConfig.class)
|
||||
public class ZipsAggregationLiveTest {
|
||||
|
||||
private static MongoClient client;
|
||||
|
||||
@Autowired
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupTests() throws Exception {
|
||||
client = new MongoClient();
|
||||
DB testDB = client.getDB("test");
|
||||
DBCollection zipsCollection = testDB.getCollection("zips");
|
||||
zipsCollection.drop();
|
||||
|
||||
InputStream zipsJsonStream = ZipsAggregationLiveTest.class.getResourceAsStream("/zips.json");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(zipsJsonStream));
|
||||
reader.lines()
|
||||
.forEach(line -> zipsCollection.insert((DBObject) JSON.parse(line)));
|
||||
reader.close();
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() throws Exception {
|
||||
client = new MongoClient();
|
||||
DB testDB = client.getDB("test");
|
||||
DBCollection zipsCollection = testDB.getCollection("zips");
|
||||
zipsCollection.drop();
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStatesHavePopGrtrThan10MillionAndSorted_thenSuccess() {
|
||||
|
||||
GroupOperation groupByStateAndSumPop = group("state").sum("pop").as("statePop");
|
||||
MatchOperation filterStates = match(new Criteria("statePop").gt(10000000));
|
||||
SortOperation sortByPopDesc = sort(new Sort(Direction.DESC, "statePop"));
|
||||
|
||||
Aggregation aggregation = newAggregation(groupByStateAndSumPop, filterStates, sortByPopDesc);
|
||||
AggregationResults<StatePopulation> result = mongoTemplate.aggregate(aggregation, "zips", StatePopulation.class);
|
||||
|
||||
/*
|
||||
* Assert that all states have population
|
||||
* greater than 10000000
|
||||
*/
|
||||
result.forEach(statePop -> {
|
||||
assertTrue(statePop.getStatePop() > 10000000);
|
||||
});
|
||||
|
||||
/*
|
||||
* Assert that states fetched are in sorted by
|
||||
* decreasing population
|
||||
*/
|
||||
List<StatePopulation> actualList = StreamSupport.stream(result.spliterator(), false)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<StatePopulation> expectedList = new ArrayList<>(actualList);
|
||||
Collections.sort(expectedList, (sp1, sp2) -> sp2.getStatePop() - sp1.getStatePop());
|
||||
|
||||
assertEquals(expectedList, actualList);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStateWithLowestAvgCityPopIsND_theSuccess() {
|
||||
|
||||
GroupOperation sumTotalCityPop = group("state", "city").sum("pop").as("cityPop");
|
||||
GroupOperation averageStatePop = group("_id.state").avg("cityPop").as("avgCityPop");
|
||||
SortOperation sortByAvgPopAsc = sort(new Sort(Direction.ASC, "avgCityPop"));
|
||||
ProjectionOperation projectToMatchModel = project().andExpression("_id").as("state")
|
||||
.andExpression("avgCityPop").as("statePop");
|
||||
LimitOperation limitToOnlyFirstDoc = limit(1);
|
||||
|
||||
Aggregation aggregation = newAggregation(sumTotalCityPop, averageStatePop, sortByAvgPopAsc, limitToOnlyFirstDoc, projectToMatchModel);
|
||||
|
||||
AggregationResults<StatePopulation> result = mongoTemplate.aggregate(aggregation, "zips", StatePopulation.class);
|
||||
StatePopulation smallestState = result.getUniqueMappedResult();
|
||||
|
||||
assertEquals("ND", smallestState.getState());
|
||||
assertTrue(smallestState.getStatePop()
|
||||
.equals(1645));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMaxTXAndMinDC_theSuccess() {
|
||||
|
||||
GroupOperation sumZips = group("state").count().as("zipCount");
|
||||
SortOperation sortByCount = sort(Direction.ASC, "zipCount");
|
||||
GroupOperation groupFirstAndLast = group().first("_id").as("minZipState")
|
||||
.first("zipCount").as("minZipCount").last("_id").as("maxZipState")
|
||||
.last("zipCount").as("maxZipCount");
|
||||
|
||||
Aggregation aggregation = newAggregation(sumZips, sortByCount, groupFirstAndLast);
|
||||
|
||||
AggregationResults<DBObject> result = mongoTemplate.aggregate(aggregation, "zips", DBObject.class);
|
||||
DBObject dbObject = result.getUniqueMappedResult();
|
||||
|
||||
assertEquals("DC", dbObject.get("minZipState"));
|
||||
assertEquals(24, dbObject.get("minZipCount"));
|
||||
assertEquals("TX", dbObject.get("maxZipState"));
|
||||
assertEquals(1671, dbObject.get("maxZipCount"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.baeldung.aggregation.model;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
public class StatePopulation {
|
||||
|
||||
@Id
|
||||
private String state;
|
||||
private Integer statePop;
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Integer getStatePop() {
|
||||
return statePop;
|
||||
}
|
||||
|
||||
public void setStatePop(Integer statePop) {
|
||||
this.statePop = statePop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("StatePopulation [state=");
|
||||
builder.append(state);
|
||||
builder.append(", statePop=");
|
||||
builder.append(statePop);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.baeldung.mongotemplate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.baeldung.config.MongoConfig;
|
||||
import org.baeldung.model.User;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MongoConfig.class)
|
||||
public class MongoTemplateProjectionLiveTest {
|
||||
|
||||
@Autowired
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
@Before
|
||||
public void testSetup() {
|
||||
if (!mongoTemplate.collectionExists(User.class)) {
|
||||
mongoTemplate.createCollection(User.class);
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mongoTemplate.dropCollection(User.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUserExists_whenAgeZero_thenSuccess() {
|
||||
mongoTemplate.insert(new User("John", 30));
|
||||
mongoTemplate.insert(new User("Ringo", 35));
|
||||
|
||||
Query query = new Query();
|
||||
query.fields()
|
||||
.include("name");
|
||||
|
||||
mongoTemplate.find(query, User.class)
|
||||
.forEach(user -> {
|
||||
assertNotNull(user.getName());
|
||||
assertTrue(user.getAge()
|
||||
.equals(0));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUserExists_whenIdNull_thenSuccess() {
|
||||
mongoTemplate.insert(new User("John", 30));
|
||||
mongoTemplate.insert(new User("Ringo", 35));
|
||||
|
||||
Query query = new Query();
|
||||
query.fields()
|
||||
.exclude("_id");
|
||||
|
||||
mongoTemplate.find(query, User.class)
|
||||
.forEach(user -> {
|
||||
assertNull(user.getId());
|
||||
assertNotNull(user.getAge());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,9 @@ import org.junit.runner.RunWith;
|
|||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mysema.query.types.Predicate;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
|
||||
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MongoConfig.class)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package org.baeldung.repository;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.baeldung.config.MongoConfig;
|
||||
import org.baeldung.model.User;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MongoConfig.class)
|
||||
public class UserRepositoryProjectionLiveTest {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private MongoOperations mongoOps;
|
||||
|
||||
@Before
|
||||
public void testSetup() {
|
||||
if (!mongoOps.collectionExists(User.class)) {
|
||||
mongoOps.createCollection(User.class);
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mongoOps.dropCollection(User.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUserExists_whenAgeZero_thenSuccess() {
|
||||
mongoOps.insert(new User("John", 30));
|
||||
mongoOps.insert(new User("Ringo", 35));
|
||||
|
||||
userRepository.findNameAndId()
|
||||
.forEach(user -> {
|
||||
assertNotNull(user.getName());
|
||||
assertTrue(user.getAge().equals(0));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUserExists_whenIdNull_thenSuccess() {
|
||||
mongoOps.insert(new User("John", 30));
|
||||
mongoOps.insert(new User("Ringo", 35));
|
||||
|
||||
userRepository.findNameAndAgeExcludeId()
|
||||
.forEach(user -> {
|
||||
assertNull(user.getId());
|
||||
assertNotNull(user.getAge());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue