0
votes

I use Spring Data MongoDb for saving documents in database.

@Repository
public interface UserRepository extends MongoRepository<User, ObjectId> {

    Optional<User> findByUsername(String userName);
    
}
@Document(collection = "users")
public class User  {

    @Id
    private ObjectId id;

    @Indexed(unique = true)
    private String username;

...
@Service
public class UserUpdateServiceImpl implements UserUpdateService {

    private UserRepository repository;

    private UserMapper mapper;

    @Autowired
    public UserUpdateServiceImpl(UserRepository repository, UserMapper mapper) {
        this.repository = repository;
        this.mapper = mapper;
    }

    @Override
    public void updateDocumentInCollection(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        repository.save(user);
    }
}

org.springframework.dao.IncorrectResultSizeDataAccessException: Query { "$java" : Query: { "username" : "user"}, Fields: {}, Sort: {} } returned non unique result.

Update_2

I used the operation insert

/**
     * Inserts the given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use the
     * returned instance for further operations as the save operation might have changed the entity instance completely.
     * Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API.
     *
     * @param entity must not be {@literal null}.
     * @return the saved entity
     * @since 1.7
     */
    <S extends T> S insert(S entity);
    public void updateUser(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        userRepository.insert(user);
    }

It again cause a mistake.

org.springframework.dao.DuplicateKeyException: E11000 duplicate key error collection: mongo-spring.users index: id dup key: { _id: ObjectId('5f3b786085c7d32787990955') }; nested exception is com.mongodb.MongoWriteException: E11000 duplicate key error collection: mongo-spring.users index: id dup key: { _id: ObjectId('5f3b786085c7d32787990955') }

Update_3

I run unit test.

   @Test
    void updateUser() {

        UserDto user = readService.getDataOfUserByName("user");

        user.setEnabled(true);
        user.setAccountNonLocked(true);

        List<Role> authorities = user.getAuthorities();
        authorities.add(Role.ADMIN);
        user.setAuthorities(authorities);


        if(user.getUsername() != null)
            userUpdateService.updateUser(user);

    }

enter image description here

    @Override
    public void updateUser(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        userRepository.save(user);

    }

enter image description here

  • mapper
public interface CommonMapper<D, E>{

    D toDto(E e);

    E toEntity(D d);

    Iterable<D> toListDto(Iterable<E> entityList);

    Iterable<E> toListEntity(Iterable<D> dtoList);
}
@Mapper(componentModel = "spring")
public interface UserMapper extends CommonMapper<UserDto, User> {
}

Now It work.

when I try to update a record, I get an exception...

1
try to use insert instead.Ismail
M.Ismail . I tried out this, but again is a mistake.skyho

1 Answers

0
votes

Your code specified that the username must be unique:

@Indexed(unique = true)
private String username;

But it appears that in your database there are multiple entries already for the username of the user that you are trying to save.

First, you need to clean up the existing duplicate entries. Then you need to decide what you want to happen in this case: do you want to update the existing object, or you want to return an error showing that the username is already taken.

In both cases you need to first lookup the existing user:

User user = repository.findByUsername(userDto.getUsername());
if(user == null) {
   user = mapper.toEntity(userDto);
}
else {
   mapper.updateUserFromDto(user, userDto);
   //OR: throw an exception
}

repository.save(user);

If your user entity is just getters/setters, and you are sure all field in your DTO are in your Entity as well, you could reuse the mapper.toEntity for updates as well, but I wouldn't recommend it:

User user = repository.findByUsername(userDto.getUsername());
if(user == null) {
   user = mapper.toEntity(userDto);
}
else {
   User updatedUser = mapper.toEntity(userDto);
   updatedUser.setId(user.getId()); // This changes the save from insert to update
   user = updatedUser;
}

repository.save(user);