使用 Spring Boot WebFlux、Spring Data MongoDB Reactive 和 ReactiveMongoRepository 更新 1 个或多个特定字段 MongoDB

Posted

技术标签:

【中文标题】使用 Spring Boot WebFlux、Spring Data MongoDB Reactive 和 ReactiveMongoRepository 更新 1 个或多个特定字段 MongoDB【英文标题】:Update 1 or multiple specific field MongoDB using Spring boot WebFlux,Spring Data MongoDB Reactive and ReactiveMongoRepository 【发布时间】:2022-01-14 02:16:59 【问题描述】:

我是 java 新手。我试图为我的 API 实现更新方法。我想更新我的数据的某些字段。 这是我的数据类:

public class Task implements Serializable 

    @Id
    private String id;
    private String task;
    private Boolean isCompleted;
    private String userId;

我的服务接口:

public interface TaskService 

    void create(Task task);

    Mono<Task> findById(String id);

    Flux<Task> findAll();

    Mono<Task> update(String Id, Task task);

    Mono<Void> delete(String id);

并为服务实施:

@Service
public class TaskServiceImpl implements TaskService 

    @Autowired
    TaskRepository taskRepository;

    public void create(Task task) 
        taskRepository.save(task).subscribe();
    

    public Mono<Task> findById(String Id) 
        return taskRepository.findById(Id);
    

    public Flux<Task> findAll() 
        return taskRepository.findAll();
    

    public Mono<Task> update(String Id, Task task) 
//        System.out.println(taskRepository.findById(Id));
        return taskRepository.findById(Id)
                .switchIfEmpty(Mono.error(new Exception("TASK_NOT_FOUND")))
                .map(b -> 
                    task.setId(Id);
                    if (task.getTask() != null) task.setTask(task.getTask());
                    if (task.getIsCompleted() != null) task.setIsCompleted(task.getIsCompleted());
                    if (task.getUserId() != null) task.setUserId(task.getUserId());
                    return task;
                )
                .flatMap(taskRepository::save);
    

    public Mono<Void> delete(String id) 
        return taskRepository.deleteById(id);
    

我的控制器:

@RestController
public class TaskController 
    @Autowired
    private TaskService taskService;

    @PostMapping("/tasks")
    @ResponseStatus(HttpStatus.CREATED)
    public void create(@RequestBody Task task) 
        taskService.create(task);
    

    @GetMapping("/tasks/id")
    public ResponseEntity<Mono<Task>> findbyId(@PathVariable("id") String Id) 
        Mono<Task> task = taskService.findById(Id);
        return new ResponseEntity<Mono<Task>>(task, task != null ? HttpStatus.OK : HttpStatus.NOT_FOUND);
    

    @GetMapping(value = "/tasks")
    @ResponseBody
    public Flux<Task> findAll() 
        return taskService.findAll();
    

    @PutMapping("/tasks/id")
    @ResponseStatus(HttpStatus.OK)
    public Mono<Task> update(@PathVariable("id") String Id, @RequestBody Task task) 
        return taskService.update(Id, task);
    

    @DeleteMapping("/tasks/id")
    @ResponseStatus(HttpStatus.OK)
    public void delete(@PathVariable("id") String id) 
        taskService.delete(id).subscribe();
    


和任务存储库:

@Repository
public interface TaskRepository extends ReactiveMongoRepository<Task, String> 

我在数据库中的数据:


    "id": "2",
    "task": "do",
    "isCompleted": true,
    "userId": "1"

我的请求正文:


    "userId": "2",
    "task": "updated"


我预计:


    "id": "2",
    "task": "updated",
    "isCompleted": true,
    "userId": "2"

但它回应了:


    "id": "2",
    "task": "updated",
    "isCompleted": null,
    "userId": "2"

它用空值更新我在请求中的缺失值。 如何更新数据中的特定值?

【问题讨论】:

奇怪的是你从数据库中检索但isCompleted字段在数据库中为空。 如果使用findById查询isComplete字段的值是多少可以调试? 如果我不发送除 ID 之外的请求正文,则所有值都为空。所以我认为它是用请求数据更新我的数据库,但是当我的请求数据丢失值时,它将为空。像这样:我的请求正文 "userId": "100" 然后我的数据: "id": "2", "task": null, "isCompleted": null, "userId": "100" 【参考方案1】:

在@Ikatiforis 之后,我已经解决了我的问题。

这是我的解决方案:

    public Mono<Task> update(String Id, Task task) 
        return taskRepository.findById(Id)
                .switchIfEmpty(Mono.error(new Exception("TASK_NOT_FOUND")))
                .map(fetchedTask  -> 
                    task.setId(Id);
                    if (task.getTask() != null 
                       fetchedTask.setTask(task.getTask());
                    if (task.getIsCompleted() != null) 
                       fetchedTask.setIsCompleted(task.getIsCompleted());
                    if (task.getUserId() != null) 
                       fetchedTask.setUserId(task.getUserId());
                    return fetchedTask;
                )
                .flatMap(taskRepository::save);
    

【讨论】:

【参考方案2】:

问题出在这里:

return taskRepository.findById(Id)
        .switchIfEmpty(Mono.error(new Exception("TASK_NOT_FOUND")))
        .map(b -> 
            task.setId(Id);
            if (task.getTask() != null) task.setTask(task.getTask());
            if (task.getIsCompleted() != null) task.setIsCompleted(task.getIsCompleted());
            if (task.getUserId() != null) task.setUserId(task.getUserId());
            return task;
        )

您完全忽略获取的Taskb 实例)并使用自己的值更新task。你可能需要这样的东西:

.map(fetchedTask -> 
       if (task.getTask() != null) 
           fetchedTask.setTask(task.getTask());
       
        return fetchedTask;
    )

【讨论】:

非常感谢。我解决了。但我必须return fetchTask。如果我return Task,那是不能改变的。

以上是关于使用 Spring Boot WebFlux、Spring Data MongoDB Reactive 和 ReactiveMongoRepository 更新 1 个或多个特定字段 MongoDB的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring boot + WebFlux 进行全局错误处理

Spring Boot Webflux/Netty - 检测关闭的连接

spring-boot-starter-web 和 spring-boot-starter-webflux 不能一起工作吗?

如何使用 Spring Boot 对 WebFlux 进行异常处理?

如何使用 WebFlux 在 Spring Boot 2 中设置登录页面?

如何使用WebFlux在Spring Boot 2中设置登录页面?