서론
Spring Boot에서 MongoDB를 사용할 때 @GeneratedValue을 사용할 수 없어 AUTO_INCREMENT를 사용할 수 없습니다. 따라서 JPA와 SQL DB를 사용할 때와 동일한 효과를 낼 수 있는 방법이 필요합니다.
이러한 문제의 해결책은 다음과 같습니다.
다른 컬렉션(테이블)에서 생성된 시퀀스를 저장할 컬렉션(테이블)을 만듭니다.
그리고 새로운 레코드를 생성할 때, 이 컬렉션을 사용하여 다음 값을 가져오면 됩니다.
코드 예시
FitTrip 프로젝트에서 적용한 코드를 예시로 들어 설명해 보겠습니다.
Collections
우선 위에서 얘기한 것과 같이 다른 컬렉션을 위한 auto-incremented sequence를 저장할 컬렉션을 만들 것입니다.
이 컬렉션의 이름을 auto_sequence라고 하겠습니다.
@Getter
@Setter
@Document(collection = "auto_sequence")
public class AutoIncrementSequence {
@Id
private String id;
private Long seq;
}
그다음 이제 서버 채팅 메시지를 저장할 ServerMessage 컬렉션과 이에 대응하는 모델 객체를 만들었습니다.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Document(collection = "serverMessages")
public class ServerMessage extends BaseModel {
@Transient
public static final String SEQUENCE_NAME = "serverMessages_sequence";
@Id
private Long messageId;
@Field
private Long serverId;
@Field
private Long channelId;
...
}
위에서 생성한 ServerMessage 모델에서는 SEQUENCE_NAME이라는 정적 필드를 추가했는데, 이는 ServerMessage
컬렉션에 대한 자동 증가 시퀀스를 고유하게 참조하는 필드입니다. 또한, ObjectId의 자동 생성을 위해 @Id가 적용된 필드의 타입은 String, ObjectId, 또는 BigInteger여야 합니다.
그리고 모델의 다른 속성과 함께 영속화되지 않도록 하기 위해 @Transient 어노테이션을 사용합니다.
@Transient 어노테이션은 해당 필드를 데이터베이스에 저장하지 않도록 지정하는 데 사용됩니다.
이를 통해 해당 필드가 데이터베이스에 저장되거나 조회될 때 포함되지 않도록 할 수 있습니다.
auto increment service
지금까지 필요한 컬렉션과 모델을 생성했습니다.
이제 엔티티의 id로 사용할 auto-incremented 값을 생성하는 서비스를 만들 것입니다.
generateSequence() 메서드를 갖춘 SequenceGenerator를 만들어 보겠습니다.
@Component
@RequiredArgsConstructor
public class SequenceGenerator {
private final MongoOperations mongoOperations;
public Long generateSequence(String seqName) {
AutoIncrementSequence counter = mongoOperations.findAndModify(query(where("_id").is(seqName)),
new Update().inc("seq", 1), options().returnNew(true).upsert(true), AutoIncrementSequence.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
}
이제, 새로운 레코드를 생성할 때 generateSequence()를 사용하여 auto increment를 적용할 수 있습니다.
@Service
@RequiredArgsConstructor
public class ServerMessageCommandServiceImpl implements ServerMessageCommandService {
private final SequenceGenerator sequenceGenerator;
private final ServerMessageRepository messageRepository;
@Override
public ServerMessageDto save(ServerMessageCreateRequest createRequest) {
ServerMessage serverMessage = ServerMessage.builder()
.serverId(createRequest.getServerId())
.channelId(createRequest.getChannelId())
...
.build();
serverMessage.generateSequence(sequenceGenerator.generateSequence(ServerMessage.SEQUENCE_NAME));
return ServerMessageDto.from(messageRepository.save(serverMessage));
}
...
}
결론
결론적으로, 우리는 id 필드에 대해 순차적으로 자동 증가 값을 생성하고, MongoDB에서도 SQL 데이터베이스의 일반적인 자동 증가 id 생성 패턴을 구현하는 방법을 살펴보았습니다.
참고
https://www.baeldung.com/spring-boot-mongodb-auto-generated-field
'프로젝트 > FitTrip' 카테고리의 다른 글
트러블 슈팅 - SockJs를 사용한 웹소켓 연결 시 CORS 이슈 (0) | 2024.07.08 |
---|---|
개발 기록 - WebSocket & STOMP 개발 이슈 (0) | 2024.07.05 |
트러블 슈팅 - IN 연산자를 활용하여 채팅 목록 조회 92% 성능 최적화 (0) | 2024.07.02 |
트러블 슈팅 - 웹소켓 연결 요청 JWT 검증 문제 (0) | 2024.06.30 |
개발 기록 - MongoDB 트랜잭션 도입 (0) | 2024.06.29 |