현재 프로젝트를 진행하면서 MongoDB를 이용하여 프로필에 관한 데이터를 아래와 같이 저장해두었다.
그리고 프론트엔드에서는 메인 페이지를 로딩할 때 아래와 같이 무한스크롤을 구현하였는데
무한스크롤을 구현할 때 No Offset방식에 대한 글을 읽게 되어 MongoDB도 B-tree구조를 사용하는 것으로 알고 있어 해당 방법을 적용해보았다.
테스트 데이터를 몇개 넣어두고 실험을 해보았었는데 첫 요청이후로 불러오질 못했다.
이유를 확인해보니 항상 반환된 document에 대해서 class-transformer의 plainToInstance()를 통해 인스턴스를 생성하는데 이때마다 해당 시점에서 새로운 ObjectId가 할당되고 있었기 때문이였다.
/* 마지막 프로필 아이디보다 오래된 프로필들 받아오기 위해 */
private ltProfileId(profileId: string): null | { _id: { $lt: ObjectId }} {
if( !profileId ) return null;
return { _id: { $lt: new ObjectId(profileId) } };
}
위와 같이 이전 요청보다 더 오래된 프로필을 불러와 최상단에는 가장 최신의 프로필이 존재하도록 하려 했지만 계속해서 최신으로 카운터가 증가한 ObjectId가 반환되고 있어 이후 요청에서 받아올 수가 없었다.
실제로 _id 값이 불일치하는지 확인해 보자.
it('plainToInstance()로 변환한 프로필 id가 기존 id와 같은지 Test', async () => {
/* 새로운 id를 생성하면서 기본 값들과 함께 */
const oldProfile = TestCaregiverProfile.default().build();
const oldProfileId = oldProfile.getId();
await caregiverProfileRepository.save(oldProfile);
const afterProfile = await caregiverProfileRepository.findById(oldProfileId);
const afterProfileId = afterProfile.getId();
expect(oldProfileId).toBe(afterProfileId);
await caregiverProfileRepository.delete(oldProfileId)
})
caregiverProfileRepository의 findById() 메서드는 내부적으로 plainToInstance()를 수행하도록 되어있다.
async findById(id: string): Promise<CaregiverProfile> {
const findProfile = await this.mongodb
.collection<CaregiverProfile>(this.collectionName)
.findOne({ _id: new ObjectId(id) });
return this.documentToInstance(findProfile);
}
/* 조회된 Document를 인스턴스로 변경 */
private documentToInstance(document: WithId<CaregiverProfile> | Document): CaregiverProfile {
return plainToInstance(CaregiverProfile, document);
}
테스트를 돌리면 위와 같이 실제로 불일치하다는 것을 확인할 수 있는데 해당 문제는 찾아본 결과 이미 class-transformer의 github issue에 등록되어 있었다.
해결법도 함께 나와있어 코드를 보면 변환을 할 때 해당 데코레이터가 달린 속성은 변환하지 않고 그대로의 값을 가져오는 것 같다.
위에 코드를 참고해서 _id 필드에 만든 데코레이터를 적용하고 난 이후에 똑같은 테스트코드를 실행해보면
기존의 _id값 그대로 유지되는 것을 확인할 수 있다.
잘 읽었습니다. 좋은 정보 감사드립니다.