У меня есть объект для сохранения (в MongoDB), но перед этим мне нужно проверить, верны ли некоторые условия.
Объект содержит идентификаторы других объектов. Это выглядит как
"object": {
"id": "123",
"subobject1": { "id": "1" },
"subobject2": { "id": "2" }
}
Подобъекты содержат только идентификатор, остальная информация находится в другой коллекции, поэтому я должен проверить, существует ли эта информация.
В блочном стиле я могу сделать что-то вроде
if (!languageRepository.exists(Example.of(wordSet.getNativeLanguage())).block()) {
throw new RuntimeException("Native language doesn't exist");
}
if (!languageRepository.exists(Example.of(wordSet.getTargetLanguage())).block()) {
throw new RuntimeException("Target language doesn't exist");
}
и только тогда я могу сохранить свой объект
return wordSetRepository.save(wordSet);
Как сделать это в "реактивном" стиле без блокировки?
Мы переходим в languageRepository, чтобы проверить, существуют ли там nativeLanguage и targetLanguage (подобъект1 и подобъект2). Если они существуют в languageRepository, мы можем сохранить этот объект (wordSet) в wordSetRepository
wordSet будет сохранен только с идентификаторами nativeLanguage и targetLanguage, а не с полными объектами. Полные объекты находятся в languageRepository.
Я имею в виду, что это за объекты? использование block() указывает на то, что languageRepository.exists - это Mono<Boolean>. Какие еще?
targetLanguage и nativeLanguage относятся к типу Language (только некоторые поля и идентификатор). WordSet содержит несколько полей (включая targetLanguage и nativeLanguage) и идентификатор.
in Если я проверю, сохранены ли уже эти объекты в languageRepository (exists (...). block ()). Если нет - исключение. Если они существуют -> сохраните набор слов (но вместо языков я сохраняю только идентификаторы языков в наборе слов).
Когда я хочу получить набор слов, я использую агрегацию для получения языков по идентификатору. Но когда я сохраняю WordSet, я хочу сохранить только идентификаторы языков (поэтому необходимо гарантировать наличие языков в другом репозитории)




Если вы хотите распространять отдельные ошибки для случаев ошибок на родном и целевом языках, вам необходимо выполнить асинхронную фильтрацию внутри flatMap:
objectFlux.flatMap(o ->
Mono.just(o)
.filterWhen(languageRepository.exists(...)) //native
.switchIfEmpty(Mono.error(new RuntimeException("Native language doesn't exist"))
.filterWhen(languageRepository.exists(...)) //target
.switchIfEmpty(Mono.error(new RuntimeException("Target language doesn't exist"))
)
.flatMap(wordSetRepository::save);
Асинхронная фильтрация внутри flatMap гарантирует, что если тест не пройдет, внутренняя последовательность будет пустой. Это, в свою очередь, позволяет нам обнаружить случай и распространить соответствующую ошибку. Если оба теста пройдены, исходный o распространяется в основной последовательности.
Второй flatMap берет его оттуда, только принимая элементы, прошедшие оба фильтра, и сохраняет их в БД.
Обратите внимание, что первый элемент, не прошедший фильтры, прервет всю последовательность (но это было то же самое в коде блокировки, так как было сгенерировано исключение).
Спасибо! Еще один вопрос: в методе должен быть входной параметр objectFlux? Я имею в виду, что этот метод находится на уровне сервиса и требует только «Object» (без Mono <Object> или Flux <Object>). Можно ли использовать только «Mono.just (object)»?
оба хороши, типичное использование Mono.just заключается в том, чтобы действовать как метод преобразования на границе, где императивный устаревший код встречается с обновленным реактивным кодом.
languageRepository.exists, Example.of, wordSet.getTargetLanguage () - что все это значит?