简体   繁体   English

如何将数据库引用与反应式 Spring Data MongoDB 一起使用?

[英]How to use db references with reactive Spring Data MongoDB?

I'm new to MongoDB and Reactor and I'm trying to retrieve a User with its Profiles associated Here's the POJO :我是 MongoDB 和 Reactor 的新手,我正在尝试检索与其关联的配置文件的用户这是 POJO:

public class User {

    private @Id String id;
    private String login;
    private String hashPassword;
    @Field("profiles") private List<String> profileObjectIds;
    @Transient private List<Profile> profiles; }

public class Profile {

    private @Id String id;
    private @Indexed(unique = true) String name;
    private List<String> roles; }

The problem is, how do I inject the profiles in the User POJO ?问题是,如何在 User POJO 中注入配置文件?

I'm aware I can put a @DBRef and solve the problem but in it's documentation, MongoDB specify manual Ref should be preferred over DB ref.我知道我可以放置一个@DBRef 并解决问题,但在它的文档中,MongoDB 指定手动 Ref 应该优先于 DB ref。

I'm seeing two solutions :我看到了两种解决方案:

  1. Fill the pojo when I get it :当我得到它时填写pojo:

     public Mono<User> getUser(String login) { return userRepository.findByLogin(login) .flatMap(user -> ??? ); }

I should do something with profileRepository.findAllById() but I don't know or to concatene both Publishers given that profiles result depends on user result.我应该对profileRepository.findAllById()做一些事情,但我不知道或连接两个发布者,因为配置文件结果取决于用户结果。

  1. Declare an AbstractMongoEventListener and override onAfterConvert method :声明一个 AbstractMongoEventListener 并覆盖 onAfterConvert 方法:

But here I am mistaken since the method end before the result is Published但是在这里我弄错了,因为方法在结果发布之前就结束了

public void onAfterConvert(AfterConvertEvent<User> event) {
    final User source = event.getSource();
    source.setProfiles(new ArrayList<>());
    profileRepository.findAllById(source.getProfileObjectIds())
    .doOnNext(e -> source.getProfiles().add(e))
    subscribe();
}

TL;DR TL; 博士

There's no DBRef support in reactive Spring Data MongoDB and I'm not sure there will be.反应式 Spring Data MongoDB 中没有DBRef支持,我不确定会有。

Explanation解释

Spring Data projects are organized into Template API, Converter and Mapping Metadata components. Spring Data 项目被组织成模板 API、转换器和映射元数据组件。 The imperative (blocking) implementation of the Template API uses an imperative approach to fetch Document s and convert these into domain objects. Template API 的命令式(阻塞)实现使用命令式方法来获取Document并将它们转换为域对象。 MappingMongoConverter in particular handles all the conversion and DBRef resolution. MappingMongoConverter特别处理所有转换和DBRef解析。 This API works in a synchronous/imperative API and is used for both Template API implementations (imperative and the reactive one).此 API 在同步/命令式 API 中工作,并用于模板 API 实现(命令式和反应式)。

Reuse of MappingMongoConverter was the logical decision while adding reactive support as we don't have a need to duplicate code.重用MappingMongoConverter是合理的决定,同时添加反应式支持,因为我们不需要重复代码。 The only limitation is DBRef resolution that does not fit the reactive execution model.唯一的限制是DBRef解析不适合反应式执行模型。

To support reactive DBRef s, the converter needs to be split up into several bits and the whole association handling requires an overhaul.为了支持无功DBRef s,转换器需要分成几个位,整个关联处理需要大修。

Reference : https://jira.spring.io/browse/DATAMONGO-2146参考: https : //jira.spring.io/browse/DATAMONGO-2146

Recommendation推荐

Keep references as keys/Id's in your domain model and look up these as needed.将引用保留为域模型中的键/ID,并根据需要查找它们。 zipWith and flatMap are the appropriate operators, depending on what you want to archive (enhance model with references, lookup references only). zipWithflatMap是合适的运算符,具体取决于您要存档的内容(使用引用增强模型,仅查找引用)。

On a related note: Reactive Spring Data MongoDB comes partially with a reduced feature set.相关说明:Reactive Spring Data MongoDB 部分带有减少的功能集。 Contextual SpEL extension is a feature that is not supported as these components assume an imperative programming model and thus synchronous execution.上下文 SpEL 扩展是一项不受支持的功能,因为这些组件采用命令式编程模型,因此采用同步执行。

For the first point, I finally achieve doing what I wanted :对于第一点,我终于做到了我想做的事:

public Mono<User> getUser(String login) {
   return userRepository.findByLogin(login)
         .flatMap( user ->
              Mono.just(user)
              .zipWith(profileRepository.findAllById(user.getProfileObjectIds())
                  .collectionList(),
                  (u, p) -> {
                       u.setProfiles(p);
                       return u;
                   })
            );
}

In my case, I have managed this problem using the follow approuch:就我而言,我使用以下方法解决了这个问题:

  1. My Entity is:我的实体是:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "post")
public class Post implements Serializable {

    private static final long serialVersionUID = -6281811500337260230L;

    @EqualsAndHashCode.Include
    @Id
    private String id;
    private Date date;
    private String title;
    private String body;
    private AuthorDto author;
    private Comment comment;
    private List<Comment> listComments = new ArrayList<>();
    private List<String> idComments = new ArrayList<>();
}
  1. My controller is:我的控制器是:
    @GetMapping(FIND_POST_BY_ID_SHOW_COMMENTS)
    @ResponseStatus(OK)
    public Mono<Post> findPostByIdShowComments(@PathVariable String id) {
        return postService.findPostByIdShowComments(id);
    }
  1. Last, but not, least, my Service (here is the solution):最后,但并非最不重要的是,我的服务(这是解决方案):
    public Mono<Post> findPostByIdShowComments(String id) {
        return postRepo
                .findById(id)
                .switchIfEmpty(postNotFoundException())
                .flatMap(postFound -> commentService
                                 .findCommentsByPostId(postFound.getId())
                                 .collectList()
                                 .flatMap(comments -> {
                                     postFound.setListComments(comments);
                                     return Mono.just(postFound);
                                 })
                        );
    }

    public Flux<Comment> findCommentsByPostId(String id) {
        return postRepo
                .findById(id)
                .switchIfEmpty(postNotFoundException())
                .thenMany(commentRepo.findAll())
                .filter(comment1 -> comment1.getIdPost()
                                            .equals(id));

    }

Thanks, this helped a lot.谢谢,这有很大帮助。 Here is my solution:这是我的解决方案:

public MappingMongoConverter mappingMongoConverter(MongoMappingContext mongoMappingContext) {
    MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mongoMappingContext);
    converter.setTypeMapper(new DefaultMongoTypeMapper(null));
    converter.setCustomConversions(mongoCustomConversions());
    return converter;
}

The trick was to use the NoOpDbRefResolver.INSTANCE诀窍是使用 NoOpDbRefResolver.INSTANCE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Spring data-mongodb-reactive从受限制的集合中流式传输 - How to stream from a capped collection with Spring data-mongodb-reactive 如何使用Spring Data MongoDB查询无效引用的文档 - How to query for documents with invalid references using spring data mongodb RSocket适用于生成的数据,但不适用于Spring Reactive MongoDB - RSocket works with generated data but not with Spring Reactive MongoDB 在 Spring Data Mongodb Reactive 中执行顺序查询 - Execute sequencial queries in Spring Data Mongodb Reactive 如何在 Reactive Spring 数据中使用来自其他对象的引用来获取对象? - How to Fetch objects, using references from other objects, in Reactive Spring Data? 如何在Spring Data Redis Reactive中使用事务? - How do I use transactions in Spring Data Redis Reactive? Spring WebFlux:Spring Data Reactive MongoDB中的block()方法返回null - Spring WebFlux: block() method return null in Spring Data Reactive MongoDB 如何使用Spring Data MongoDB进行乐观锁定? - How to use optimistic locking with Spring Data MongoDB? Java Spring数据mongodb如何使用通配符? - Java Spring data mongodb how to use wildcards? 如何在Spring-Data中使用MongoDB $ let? - How to use MongoDB $let with Spring-Data?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM