Перейти к основному содержимому

Настройте имя коллекции MongoDB для класса в Spring Data

· 7 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

В этом руководстве мы узнаем, как настроить имена коллекций MongoDB для наших классов, а также рассмотрим практический пример. Мы будем использовать Spring Data , что дает нам несколько вариантов для достижения этого с небольшой настройкой. Мы рассмотрим каждый вариант, создав простой музыкальный магазин. Таким образом, мы можем узнать, когда имеет смысл их использовать.

2. Пример использования и настройка

В нашем варианте использования есть четыре простых класса: MusicAlbum , Compilation , MusicTrack и Store . Имя коллекции каждого класса будет настроено по-разному. Также у каждого класса будет свой MongoRepository . Никаких пользовательских запросов не потребуется. Кроме того, нам понадобится правильно настроенный экземпляр базы данных MongoDB .

2.1. Сервис для перечисления содержимого коллекции по имени

Во-первых, давайте напишем контроллер , чтобы убедиться, что наши конфигурации работают. Мы сделаем это, выполнив поиск по названию коллекции. Обратите внимание, что при использовании репозиториев конфигурации имен коллекций прозрачны:

@RestController
@RequestMapping("/collection")
public class CollectionController {
@Autowired
private MongoTemplate mongoDb;

@GetMapping("/{name}")
public List<DBObject> get(@PathVariable String name) {
return mongoDb.findAll(DBObject.class, name);
}
}

Этот контроллер основан на MongoTemplate и использует универсальный тип DBObject , который не зависит от классов и репозиториев. Кроме того, таким образом мы сможем увидеть внутренние свойства MongoDB. Самое главное, свойство «_class», используемое Spring Data для демаршалирования объекта JSON, гарантирует правильность нашей конфигурации.

2.2. Служба API

Во-вторых, мы начнем создавать наш сервис, который просто сохраняет объекты и извлекает их коллекцию. Класс Compilation будет создан позже в нашем первом примере конфигурации :

@Service
public class MusicStoreService {
@Autowired
private CompilationRepository compilationRepository;

public Compilation add(Compilation item) {
return compilationRepository.save(item);
}

public List<Compilation> getCompilationList() {
return compilationRepository.findAll();
}

// other service methods
}

2.3. Конечные точки API

Наконец, давайте напишем контроллер для взаимодействия с нашим приложением. Мы предоставим конечные точки для наших методов обслуживания:

@RestController
@RequestMapping("/music")
public class MusicStoreController {
@Autowired
private MusicStoreService service;

@PostMapping("/compilation")
public Compilation post(@RequestBody Compilation item) {
return service.add(item);
}

@GetMapping("/compilation")
public List<Compilation> getCompilationList() {
return service.getCompilationList();
}

// other endpoint methods
}

После этого мы готовы приступить к настройке наших классов.

3. Конфигурация с аннотацией @Document

Доступная начиная с Spring Data версии 1.9, аннотация Document делает все, что нам нужно. Это специфично для MongoDB, но похоже на аннотацию Entity JPA . `` На момент написания этой статьи невозможно определить стратегию именования для имен коллекций, только для имен полей. Поэтому давайте изучим то, что доступно.

3.1. Поведение по умолчанию

По умолчанию считается, что имя коллекции совпадает с именем класса, но начинается с нижнего регистра. Короче говоря, нам просто нужно добавить аннотацию документа , и все заработает :

@Document
public class Compilation {
@Id
private String id;

// getters and setters
}

После этого все вставки из нашего репозитория Compilation попадут в коллекцию с именем «compilation» в MongoDB:

$ curl -X POST http://localhost:8080/music/compilation -H 'Content-Type: application/json' -d '{
"name": "Spring Hits"
}'

{ "id": "6272e26e04a673360d926ca1" }

Давайте перечислим содержимое нашей коллекции «компиляции», чтобы проверить нашу конфигурацию:

$ curl http://localhost:8080/collection/compilation

[
{
"name": "Spring Hits",
"_class": "com.foreach.boot.collection.name.data.Compilation"
}
]

И это самый чистый способ настроить имя коллекции, поскольку оно в основном совпадает с именем нашего класса. Одним из недостатков является то, что если мы решим изменить наши соглашения об именовании баз данных, нам потребуется реорганизовать все наши классы. Например, если мы решим использовать змеиный регистр для имен наших коллекций, мы не сможем воспользоваться поведением по умолчанию.

3.2. Переопределение свойства value

Аннотация документа позволяет нам переопределить поведение по умолчанию с помощью свойства коллекции . Поскольку это свойство является псевдонимом свойства value , мы можем установить его неявно:

@Document("albums")
public class MusicAlbum {
@Id
private String id;

private String name;

private String artist;

// getters and setters
}

Теперь вместо документов, попадающих в коллекцию «musicAlbum», они будут попадать в коллекцию «albums». Это самый простой способ настроить имя коллекции с помощью Spring Data . Чтобы увидеть это в действии, давайте добавим альбом в нашу коллекцию:

$ curl -X POST 'http://localhost:8080/music/album' -H 'Content-Type: application/json' -d '{
"name": "Album 1",
"artist": "Artist A"
}'

{ "id": "62740de003d2452a61a75c35" }

Затем мы можем получить нашу коллекцию «альбомов», убедившись, что наша конфигурация работает:

$ curl 'http://localhost:8080/collection/albums'

[
{
"name": "Album 1",
"artist": "Artist A",
"_class": "com.foreach.boot.collection.name.data.MusicAlbum"
}
]

Кроме того, это отлично подходит для адаптации нашего приложения к существующей базе данных с именами коллекций, которые не соответствуют нашим классам. Единственным недостатком является то, что если бы нам нужно было добавить префикс по умолчанию, нам пришлось бы делать это для каждого класса.

3.3. Использование свойства конфигурации с SpEL

Эта комбинация может помочь сделать то, что невозможно с помощью одной только аннотации документа . Мы начнем со специфичного для приложения свойства, которое мы хотим повторно использовать в наших классах.

Во-первых, давайте добавим свойство в наш application.properties , которое мы будем использовать в качестве суффикса к именам наших коллекций :

collection.suffix=db

Теперь давайте сошлемся на него с помощью SpEL через компонент среды , чтобы создать наш следующий класс:

@Document("store-#{@environment.getProperty('collection.suffix')}")
public class Store {
@Id
private String id;

private String name;

// getters and setters
}

Затем давайте создадим наш первый магазин:

$ curl -X POST 'http://localhost:8080/music/store' -H 'Content-Type: application/json' -d '{
"name": "Store A"
}'

{ "id": "62744c6267d3a034ec5e5719" }

В результате наш класс будет храниться в коллекции с именем «store-db». Опять же, мы можем проверить нашу конфигурацию, перечислив ее содержимое:

$ curl 'http://localhost:8080/collection/store-db'

[
{
"name": "Store A",
"_class": "com.foreach.boot.collection.name.data.Store"
}
]

Таким образом, если мы изменим наш суффикс, нам не придется вручную менять его в каждом классе. Вместо этого мы просто обновляем наш файл свойств. Недостатком является то, что это более шаблонно, и нам все равно придется писать имя класса. Тем не менее, это также может помочь с поддержкой нескольких арендаторов . Например, вместо суффикса мы могли бы использовать идентификатор арендатора, чтобы помечать коллекции, которые не являются общими.

3.4. Использование метода Bean с SpEL

Еще одним недостатком использования SpEL является то, что для его программной оценки требуется дополнительная работа. Но это открывает множество возможностей, таких как вызов любого метода компонента для определения имени нашей коллекции. Итак, в нашем следующем примере мы создадим bean-компонент для исправления имени коллекции в соответствии с нашими правилами именования .

В нашей стратегии именования мы будем использовать змеиный регистр. Во-первых, давайте позаимствуем код из Spring Data SnakeCaseFieldNamingStrategy для создания нашего служебного компонента:

public class Naming {
public String convert(String name) {
List<String> parts = ParsingUtils.splitCamelCaseToLower(name);
List<String> result = new ArrayList<>();

for (String part : parts) {
if (StringUtils.hasText(part)) {
result.add(part);
}
}

return StringUtils.collectionToDelimitedString(result, "_");
}
}

Далее добавим этот bean-компонент в наше приложение:

@SpringBootApplication
public class SpringBootCollectionNameApplication {

// main method

@Bean
public Naming naming() {
return new Naming();
}
}

После этого мы сможем ссылаться на наш бин через SpEL:

@Document("#{@naming.fix('MusicTrack')}")
public class MusicTrack {
@Id
private String id;

private String name;

private String artist;

// getters and setters
}

Давайте попробуем, добавив элемент в нашу коллекцию:

$ curl -X POST 'http://localhost:8080/music/track' -H 'Content-Type: application/json' -d '{
"name": "Track 1",
"artist":"Artist A"
}'

{ "id": "62755987ae94c5278b9530cc" }

Следовательно, наш трек будет храниться в коллекции с именем «music_track»:

$ curl 'http://localhost:8080/collection/music_track'

[
{
"name": "Track 1",
"artist": "Artist A",
"_class": "com.foreach.boot.collection.name.data.MusicTrack"
}
]

К сожалению, нет возможности получить имя класса динамически, что является серьезным недостатком , но это позволяет изменять правила именования нашей базы данных без необходимости вручную переименовывать все наши классы.

4. Вывод

В этой статье мы рассмотрели способы настройки имен наших коллекций с помощью инструментов, которые нам предоставляет Spring Data. Кроме того, мы увидели преимущества и недостатки каждого, поэтому можем решить, что лучше всего подходит для конкретного сценария. В ходе этого мы создали простой пример использования, чтобы продемонстрировать различные подходы.

И, как всегда, исходный код доступен на GitHub .