Spring реактивный - обновить вложенные объекты в списке, а затем сохранить родительский объект - PullRequest
2 голосов
/ 30 марта 2019

У меня есть корневой объект, у которого есть вложенный список объектов.Мне нужно получить доступ к этому вложенному списку объектов, предварительно выполнить некоторые действия с ними и затем сохранить результаты обратно.

Кажется, я запутался во вложенном flatMaps.

Лучшее, что мне удалось придумать, это:

public Flux<Face> scanSingleVideo(@PathVariable final String id) {

    // Reactive MongoDB Find by ID
    return videoRepository.findById(id)

            // A single video is returned, the video has an ArrayList of thumbnails
            .flatMapMany(video -> Flux.fromIterable(video.getThumbnails()))

            // Each thumbnail has a 'path' value which is just a string
            .map(Thumbnail::getPath)

            // Passing the path into a function which does some business work. The function returns a Flux of faces
            .flatMap(faceService::detectFaces);

            // Q: How can I get these new objects into an array on the Thumbnail, then save the video object with the updated thumbnail? 
}

Но я застрял, если это даже верное направление.Для контекста вот два домена, с которыми я работаю

Видеообъект

public class Video {
    // {..}
    List<Thumbnail> thumbnails = new ArrayList<>();
}

Миниатюра объекта

public class Thumbnail {
    // {..}
    String path;

    Set<Face> faces = new HashSet<>();
}

Первая попытка, которая мне показалась близкой, когда она установила новые объекты на Thumbnail, но очень уродливая и кажется, что я где-то ошибся или пропустил ключевой метод, который мог бы использовать.Это, однако, работает.

public Mono<Video> scanSingleVideo(@PathVariable final String id) {
    return videoRepository.findById(id)
            .flatMap(video -> {
                video.getThumbnails().forEach(thumbnail -> faceService
                        .detectFaces(thumbnail.getPath())
                        .flatMap(face -> {
                            thumbnail.getFaces().add(face);

                            return Mono.just(thumbnail);
                        }).flatMap(t -> {
                            video.getThumbnails().add(t);

                            return videoRepository.save(video);
                        }).subscribe());

                return videoRepository.save(video);
            });
}

Мне не нравится вложенная подписка, но я не уверен, как еще подойти к этому.


Редактировать : Для любого, кто сталкивается с этим, вы можете немного убрать мою «рабочую» попытку, но я все еще не думаю, что это правильно.

public Mono<Video> scanSingleVideo(@PathVariable final String id) {
    return videoRepository.findById(id)
            .flatMap(video -> {
                video.getThumbnails().forEach(thumbnail -> faceService
                        .detectFaces(thumbnail.getPath())
                        .flatMap(face -> getPublisher(video, thumbnail, face))
                        .distinct()
                        .subscribe());

                return videoRepository.save(video);
            });
}

private Publisher<? extends Video> getPublisher(Video video, Thumbnail thumbnail, Face face) {
    thumbnail.getFaces().add(face);
    video.getThumbnails().add(thumbnail);

    return videoRepository.save(video);
}
...