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

时间:2018-04-27 09:00:18

标签: java mongodb spring-data-mongodb

我是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; }

问题是,如何在用户POJO中注入配置文件?

我知道我可以放一个@DBRef并解决问题,但在其文档中,MongoDB指定手册Ref应优先于DB ref。

我看到了两个解决方案:

  1. 当我拿到它时填充pojo:

    public Mono<User> getUser(String login) {
        return userRepository.findByLogin(login)
        .flatMap(user -> ??? );
    }
    
  2. 我应该使用 profileRepository.findAllById()做一些事情,但我不知道或联系两个发布者,因为个人资料结果取决于用户结果。

    1. 声明一个AbstractMongoEventListener并覆盖onAfterConvert方法:
    2. 但是在这里我错了,因为方法在结果发布之前结束

      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();
      }
      

3 个答案:

答案 0 :(得分:1)

TL; DR

在响应式Spring Data MongoDB中没有DBRef支持,我不确定会有。{/ p>

解释

Spring Data项目被组织成Template API,Converter和Mapping Metadata组件。模板API的命令式(阻塞)实现使用命令式方法来获取Document并将它们转换为域对象。 MappingMongoConverter特别处理所有转换和DBRef解析。此API在同步/命令式API中工作,并用于模板API实现(命令性和反应式)。

在添加反应支持时,重复使用MappingMongoConverter是合乎逻辑的决定,因为我们不需要复制代码。唯一的限制是DBRef分辨率不适合被动执行模型。

为了支持无效DBRef,转换器需要分成几个位,整个关联处理需要进行大修。

建议

将引用保留为域模型中的键/ ID,并根据需要查找这些内容。 zipWithflatMap是适当的运算符,具体取决于您要归档的内容(使用引用增强模型,仅查找引用)。

相关说明:响应式Spring Data MongoDB还支持其他一些功能,例如Querydsl,审计,上下文SpEL扩展,因为现有组件采用命令式编程模型,因此同步执行。

答案 1 :(得分:0)

首先,我终于实现了我想要的目标:

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;
                   })
            );
}

答案 2 :(得分:0)

就我而言,我使用以下方法解决了这个问题:

  1. 我的实体是:
await admin.firestore().collection('globalPosts').orderBy("date_created", "desc")
.get()
.then(function(querySnapshot) {
    if(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
        return null
    }
    else {
        throw new Error("Data doesn't exist")
    }
})
  1. 我的控制器是:
@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. 最后,但并非最不重要的是,我的服务(这是解决方案):
    @GetMapping(FIND_POST_BY_ID_SHOW_COMMENTS)
    @ResponseStatus(OK)
    public Mono<Post> findPostByIdShowComments(@PathVariable String id) {
        return postService.findPostByIdShowComments(id);
    }