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 +
'}';
}
}