[英]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 :我看到了两种解决方案:
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()做一些事情,但我不知道或连接两个发布者,因为配置文件结果取决于用户结果。
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();
}
There's no DBRef
support in reactive Spring Data MongoDB and I'm not sure there will be.反应式 Spring Data MongoDB 中没有DBRef
支持,我不确定会有。
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
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). zipWith
和flatMap
是合适的运算符,具体取决于您要存档的内容(使用引用增强模型,仅查找引用)。
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:就我而言,我使用以下方法解决了这个问题:
@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<>();
}
@GetMapping(FIND_POST_BY_ID_SHOW_COMMENTS)
@ResponseStatus(OK)
public Mono<Post> findPostByIdShowComments(@PathVariable String id) {
return postService.findPostByIdShowComments(id);
}
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.