1. Introducción
En el siguiente post veremos como conectarnos a una instancia de MongoDB a través de Spring Data. Para ello necesitaremos:
- Añadir dependencias Spring Data
- Configurar conexión
Si quieres ver como instalar MongoDB en local y saber un poco más ir a Primeros pasos en MongoDB
Os podéis descargar el código de ejemplo de mi GitHub aquí.
Tecnologías empleadas:
- Java 8
- Gradle 3.1
- Spring-Test 4.3.7.RELEASE
- SpringData-MongoDB 1.10.1.RELEASE
2. Colección y documentos
La colección y documentos que vamos a utilizar son los que se han creado e insertado en el post Primeros pasos en MongoDB
Colección
User
Documentos
db.user.insert({"_id":"1","name":"admin","surname":"admin","gender":"male","roles":["ROLE_ADMIN"]}) db.user.insert({"_id":"2","name":"Jorge","surname":"HernándezRamírez","gender":"male","roles":["ROLE_ADMIN"],"teams":[{"name":"UD.LasPalmas","sport":"Football"},{"name":"RealMadrid","sport":"Football"},{"name":"McLaren","sport":"F1"}]}) db.user.insert({"_id":"3","name":"Jose","gender":"male","surname":"HernándezRamírez","roles":["ROLE_USER"],"teams":[{"name":"UD.LasPalmas","sport":"Football"},{"name":"MagnusCarlsen","sport":"Chess"}]}) db.user.insert({"_id":"4","name":"Raul","surname":"GonzálezBlanco","gender":"male","roles":["ROLE_USER"],"teams":[{"name":"RealMadrid","sport":"Football"},{"name":"RealMadrid","sport":"Basketball"}]}) db.user.insert({"_id":"5","name":"Constanza","surname":"RamírezRodríguez","gender":"female","roles":["ROLE_USER"],"teams":[{"name":"UD.LasPalmas","sport":"Football"}]})
3. Ficheros
Dependencias
Añadimos la dependencia spring-data-mongodb
group 'com.jorgehernandezramirez.spring.springdata' version '1.0-SNAPSHOT' apply plugin: 'java' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'org.springframework.data', name: 'spring-data-mongodb', version: spring_data_mongodb_version testCompile group: 'org.springframework', name: 'spring-test', version: spring_test_version testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.2' testCompile group: 'junit', name: 'junit', version: junit_version }
Configuración
Se muestra la configuración para conectar con nuestra base de datos que se encuentra en localhost:27017.
package com.jorgehernandezramirez.spring.springdata.mongodb.configuration; import com.mongodb.Mongo; import com.mongodb.MongoClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.config.AbstractMongoConfiguration; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @Configuration @EnableMongoRepositories(basePackages = "com.jorgehernandezramirez.spring.springdata.mongodb.repository") public class MongoDBConfiguration extends AbstractMongoConfiguration { @Override public MongoMappingContext mongoMappingContext() throws ClassNotFoundException { return super.mongoMappingContext(); } @Override @Bean public Mongo mongo() throws Exception { return new MongoClient("localhost" + ":" + "27017"); } @Override protected String getDatabaseName() { return "development"; } }
Se muestra el repositorio y la entidad asociada a la colección user
package com.jorgehernandezramirez.spring.springdata.mongodb.repository; import com.jorgehernandezramirez.spring.springdata.mongodb.entity.UserEntity; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.Query; import java.util.List; /** * Repository de la entidad User */ public interface UserRepository extends MongoRepository<UserEntity, String> { List<UserEntity> findByName(String name); @Query("{'teams.name': ?0}") List<UserEntity> findByTeamname(String teamName); }
package com.jorgehernandezramirez.spring.springdata.mongodb.entity; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import java.util.List; @Document(collection = "user") public class UserEntity { @Id private String id; private String name; private String surname; private String gender; private List<String> roles; private List<Team> teams; public UserEntity(){ //For Spring Data } public UserEntity(String id, String name, String surname, String gender, List<String> roles, List<Team> teams) { this.id = id; this.name = name; this.surname = surname; this.gender = gender; this.roles = roles; this.teams = teams; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public List<String> getRoles() { return roles; } public void setRoles(List<String> roles) { this.roles = roles; } public List<Team> getTeams() { return teams; } public void setTeams(List<Team> teams) { this.teams = teams; } @Override public String toString() { return "UserEntity{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", surname='" + surname + '\'' + ", gender='" + gender + '\'' + ", roles=" + roles + ", teams=" + teams + '}'; } }
package com.jorgehernandezramirez.spring.springdata.mongodb.entity; public class Team { private String name; private String sport; public Team(){ //For Spring Data } public Team(String name, String sport) { this.name = name; this.sport = sport; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSport() { return sport; } public void setSport(String sport) { this.sport = sport; } @Override public String toString() { return "Team{" + "name='" + name + '\'' + ", sport='" + sport + '\'' + '}'; } }
4. Testeando nuestro repositorio
Test
package com.jorgehernandezramirez.spring.springdata.mongodb; import com.jorgehernandezramirez.spring.springdata.mongodb.configuration.MongoDBConfiguration; import com.jorgehernandezramirez.spring.springdata.mongodb.entity.Count; import com.jorgehernandezramirez.spring.springdata.mongodb.entity.UserEntity; import com.jorgehernandezramirez.spring.springdata.mongodb.entity.UserGenderCount; import com.jorgehernandezramirez.spring.springdata.mongodb.repository.UserRepository; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; 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.query.Criteria; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; import static org.junit.Assert.assertNotNull; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MongoDBConfiguration.class,loader=AnnotationConfigContextLoader.class) public class MongoDBTest { private static final Logger LOGGER = LoggerFactory.getLogger(MongoDBTest.class); @Autowired private MongoTemplate mongoTemplate; @Autowired private UserRepository userRepository; @Test public void shouldBeNotNullMongoTemplate(){ assertNotNull(mongoTemplate); assertNotNull(userRepository); } @Test public void shouldReturnAllUsersFromDB(){ userRepository.findAll().forEach(userEntity -> { LOGGER.info("{}", userEntity); }); } @Test public void shouldReturnAllUsersFromUsername(){ userRepository.findByName("Jorge").forEach(userEntity -> { LOGGER.info("{}", userEntity); }); } @Test public void shouldReturnAllUsersLikeUDLasPalmas(){ userRepository.findByTeamname("UD. Las Palmas").forEach(userEntity -> { LOGGER.info("{}", userEntity); }); }
Utilizando agregaciones
Obtener el número de chicos y chicas en el sistema
Análogo a la siguiente query
@Test public void shouldGetNumberOfMenAndWomens(){ final Aggregation aggregation = newAggregation( group("gender").count().as("count"), project("count").and("gender").previousOperation()); final AggregationResults<UserGenderCount> groupResults = mongoTemplate.aggregate(aggregation, UserEntity.class, UserGenderCount.class); LOGGER.info("{}", groupResults.getMappedResults()); }
Se mapean los datos sobre UserGenderCount
package com.jorgehernandezramirez.spring.springdata.mongodb.entity; public class UserGenderCount { private String gender; private Integer count; public UserGenderCount(){ //For Spring Data } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } @Override public String toString() { return "UserGenderCount{" + "gender='" + gender + '\'' + ", count=" + count + '}'; } }
Obtener el número de veces que el Real Madrid es un equipo favorito de un usuario
Análogo a la siguiente query
db.user.aggregate( {$unwind: "$teams"}, {$match: {"teams.name": "Real Madrid"}}, {$group: {_id: null, count: {$sum: 1}}} )
@Test public void shouldGetNumberRealMadridLikers(){ final Aggregation aggregation = newAggregation( unwind("teams"), match(Criteria.where("teams.name").is("Real Madrid")), group().count().as("count"), project("count")); final AggregationResults<Count> groupResults = mongoTemplate.aggregate(aggregation, UserEntity.class, Count.class); LOGGER.info("{}", groupResults.getMappedResults()); }
Se muestra la clase sobre la que se mapeará el resultado
package com.jorgehernandezramirez.spring.springdata.mongodb.entity; public class Count { private Integer count; public Count(){ //For Spring Data } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } @Override public String toString() { return "Count{" + "count=" + count + '}'; } }