Skip to content
Advertisement

Update 1 or multiple specific field MongoDB using Spring boot WebFlux,Spring Data MongoDB Reactive and ReactiveMongoRepository

I’m newbie with java. I tried to implement update method for my API. I want to update some field of my data. Here is my data class:

public class Task implements Serializable {

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

My service interface:

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

And implement for services:

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

My Controller:

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

And Task Repository:

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

My data in DB:

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

My request body:

{
    "userId": "2",
    "task": "updated"
}
}

I expected:

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

But it responsed:

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

It update my missing value in request with null value. How can I update specific values in data?

Advertisement

Answer

The problem is here:

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

You completely ignore the fetched Task (b instance) and update the task with its own values. You probably need something like this:

.map(fetchedTask -> {
       if (task.getTask() != null) {
           fetchedTask.setTask(task.getTask());
       }
        return fetchedTask;
    })
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement