Введение в Spring Data MongoDB
1. обзор
Эта статья будет быстрой и практичнойintroduction to Spring Data MongoDB.
Мы рассмотрим основы, используя какMongoTemplate, так иMongoRepository, используя практические примеры для иллюстрации каждой операции.
Дальнейшее чтение:
Геопространственная поддержка в MongoDB
Узнайте, как хранить, индексировать и искать геопространственные данные с MongoDB
Тестирование интеграции с Spring Boot с помощью встроенного MongoDB
Узнайте, как использовать встроенное решение MongoDB от Flapdoodle вместе со Spring Boot для бесперебойного выполнения интеграционных тестов MongoDB.
2. MongoTemplateand MongoRepository
The MongoTemplate следует стандартному шаблону в Spring и предоставляет готовый базовый API для базового механизма сохранения.
The repository следует подходу Spring, ориентированному на данные, и поставляется с более гибкими и сложными операциями API, основанными на хорошо известных шаблонах доступа во всех проектах Spring Data.
Для обоих нам нужно начать с определения зависимости - например, вpom.xml с Maven:
org.springframework.data
spring-data-mongodb
2.1.9.RELEASE
org.springframework.data
spring-data-releasetrain
Lovelace-SR9
pom
import
Чтобы проверить, выпущена ли какая-либо новая версия библиотеки -track the releases here.
3. Конфигурация дляMongoTemplate
3.1. Конфигурация XML
Давайте начнем с простой конфигурации XML для шаблона Mongo:
Во-первых, нам нужно определить фабричный компонент, отвечающий за создание экземпляров Mongo.
Далее - нам нужно определить (и настроить) шаблонный компонент:
И, наконец, нам нужно определить постпроцессор для перевода любыхMongoExceptions, добавленных в аннотированные классы@Repository:
3.2. Конфигурация Java
Теперь давайте создадим аналогичную конфигурацию с использованием конфигурации Java, расширив базовый класс для конфигурации MongoDBAbstractMongoConfiguration:
@Configuration
public class MongoConfig extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "test";
}
@Override
public MongoClient mongoClient() {
return new MongoClient("127.0.0.1", 27017);
}
@Override
protected String getMappingBasePackage() {
return "org.example";
}
}
Примечание. Нам не нужно было определять bean-компонентMongoTemplate в предыдущей конфигурации, поскольку он уже определен вAbstractMongoConfiguration.
Мы также можем использовать нашу конфигурацию с нуля без расширенияAbstractMongoConfiguration - следующим образом:
@Configuration
public class SimpleMongoConfig {
@Bean
public MongoClient mongo() {
return new MongoClient("localhost");
}
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), "test");
}
}
4. Конфигурация дляMongoRepository
4.1. Конфигурация XML
Чтобы использовать пользовательские репозитории (расширениеMongoRepository) - нам нужно продолжить настройку из раздела 3.1 и настроить репозитории:
4.2. Конфигурация Java
Точно так же мы воспользуемся конфигурацией, которую мы уже создали в разделе 3.2, и добавим в смесь новую аннотацию:
@EnableMongoRepositories(basePackages = "org.example.repository")
4.3. Создать репозиторий
Теперь, после настройки, нам нужно создать репозиторий - расширяя существующий интерфейсMongoRepository:
public interface UserRepository extends MongoRepository {
//
}
Теперь мы можем автоматически подключить этотUserRepository и использовать операции изMongoRepository или добавить пользовательские операции.
5. ИспользуяMongoTemplate
5.1. Insertс
Начнем с операции вставки; начнем также с пустой базы данных:
{
}
Теперь, если мы добавим нового пользователя:
User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");
База данных будет выглядеть так:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "org.example.model.User",
"name" : "Jon"
}
5.2. Save – Insertс
Операцияsave имеет семантику сохранения или обновления: если идентификатор присутствует, она выполняет обновление, если нет - выполняет вставку.
Давайте посмотрим на первую семантику - вставку; вот начальное состояние базы данных:
{
}
Когда мы теперьsave новый пользователь:
User user = new User();
user.setName("Albert");
mongoTemplate.save(user, "user");
Объект будет вставлен в базу данных:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Albert"
}
Затем мы рассмотрим ту же операцию -save - с семантикой обновления.
5.3. Save – Updateс
Теперь посмотрим наsave с семантикой обновления, работающий с существующей сущностью:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Jack"
}
Теперь, когда мыsave существующий пользователь - мы обновим его:
user = mongoTemplate.findOne(
Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");
База данных будет выглядеть так:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Jim"
}
Как видите, в этом конкретном примереsave использует семантикуupdate, потому что мы используем объект с заданным_id.
5.4. UpdateFirstс
updateFirst обновляет самый первый документ, соответствующий запросу.
Начнем с начального состояния базы данных:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Alex"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "org.example.model.User",
"name" : "Alex"
}
]
Теперь, когда мы запускаемupdateFirst:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);
Только первая запись будет обновлена:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "James"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "org.example.model.User",
"name" : "Alex"
}
]
5.5. UpdateMultiс
UpdateMultiupdates all document that matches the given query.
Во-первых, вот состояние базы данных до выполненияupdateMulti:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Eugen"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "org.example.model.User",
"name" : "Eugen"
}
]
Теперь давайте запустим операциюupdateMulti:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eugen"));
Update update = new Update();
update.set("name", "Victor");
mongoTemplate.updateMulti(query, update, User.class);
Оба существующих объекта будут обновлены в базе данных:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Victor"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "org.example.model.User",
"name" : "Victor"
}
]
5.6. FindAndModifyс
Эта операция работает какupdateMulti, но этоreturns the object before it was modified.
Сначала - состояние базы данных перед вызовомfindAndModify:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Markus"
}
Давайте посмотрим на реальный код операции:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
User user = mongoTemplate.findAndModify(query, update, User.class);
Возвращенныйuser object имеет те же значения, что и исходное состояние в базе данных.
Тем не менее, новое состояние в базе данных:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Nick"
}
5.7. Upsertс
upsert работает сfind and modify else create semantics: если документ соответствует, обновите его, иначе создайте новый документ, комбинируя запрос и объект обновления.
Начнем с начального состояния базы данных:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Markus"
}
Теперь - давайте запустимupsert:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
mongoTemplate.upsert(query, update, User.class);
Вот состояние базы данных после операции:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Nick"
}
5.8. Removeс
Состояние базы данных до вызоваremove:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Benn"
}
Теперь запустимremove:
mongoTemplate.remove(user, "user");
Результат будет таким, как ожидалось:
{
}
6. ИспользуяMongoRepository
6.1. Insertс
Во-первых - состояние базы данных перед запускомinsert:
{
}
Теперь, когда мы вставляем нового пользователя:
User user = new User();
user.setName("Jon");
userRepository.insert(user);
Вот конечное состояние базы данных:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "org.example.model.User",
"name" : "Jon"
}
Обратите внимание, как эта операция работает так же, какinsert в APIMongoTemplate.
6.2. Save -Insert
Аналогично -save работает так же, как операцияsave в APIMongoTemplate.
Начнем с рассмотренияthe insert semantics операции; вот начальное состояние базы данных:
{
}
Теперь - выполняем операциюsave:
User user = new User();
user.setName("Aaron");
userRepository.save(user);
Это приводит к добавлению пользователя в базу данных:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Aaron"
}
Еще раз обратите внимание, как в этом примереsave работает с семантикойinsert, потому что мы вставляем новый объект.
6.3. Save -Update
Давайте теперь посмотрим на ту же операцию, но сupdate semantics.
Во-первых, вот состояние базы данных до запуска новогоsave:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Jack"81*6
}
Сейчас - мы выполняем операцию:
user = mongoTemplate.findOne(
Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);
Наконец, вот состояние базы данных:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.example.model.User",
"name" : "Jim"
}
Еще раз обратите внимание, как в этом примереsave работает с семантикойupdate, потому что мы используем существующий объект.
6.4. Deleteс
Состояние базы данных до вызоваdelete:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Benn"
}
Запустимdelete:
userRepository.delete(user);
Результатом будет просто:
{
}
6.5. FindOneс
Состояние базы данных при вызовеfindOne:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Chris"
}
Теперь выполнимfindOne:
userRepository.findOne(user.getId())
Результат, который вернет существующие данные:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Chris"
}
6.6. Existsс
Состояние базы данных до вызоваexists:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Harris"
}
Теперь запустимexists:
boolean isExists = userRepository.exists(user.getId());
Что, конечно, вернетtrue.
6.7. FindAll #with[.pl-en] Sort#
Состояние базы данных до вызоваfindAll:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Brendan"
},
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Adam"
}
]
Теперь запустимfindAll сSort:
List users = userRepository.findAll(new Sort(Sort.Direction.ASC, "name"));
Результатом будетsorted by name in ascending order:
[
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Adam"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Brendan"
}
]
6.8. FindAll #with[.pl-en] Pageable #
Состояние базы данных до вызоваfindAll:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Brendan"
},
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Adam"
}
]
Теперь выполнимfindAll с запросом разбивки на страницы:
Pageable pageableRequest = PageRequest.of(0, 1);
Page page = userRepository.findAll(pageableRequest);
List users = pages.getContent();
В результате в спискеusers будет только один пользователь: __
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.example.model.User",
"name" : "Brendan"
}
7. Аннотации
Наконец, давайте также рассмотрим простые аннотации, которые Spring Data использует для управления этими операциями API.
@Id
private String id;
Аннотация уровня поля@Id может украшать любой тип, включаяlong иstring.
Если значение поля@Id не равно нулю, оно сохраняется в базе данных как есть; в противном случае конвертер предположит, что вы хотите сохранитьObjectId в базе данных (работает либоObjectId, String, либоBigInteger).
Далее -@Document:
@Document
public class User {
//
}
Эта аннотация простоmarks a class as being a domain object, которая должна быть сохранена в базе данных, а также позволяет нам выбрать имя коллекции, которая будет использоваться.
8. Заключение
Эта статья была быстрым, но исчерпывающим введением в использование MongoDB с данными Spring, как через APIMongoTemplate, так и с использованиемMongoRepository.
Реализация всех этих примеров и фрагментов кодаcan be foundover on Github - это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.