findOne() / findOneBy()의 차이점을 알아보자!
TypeORM이 제공하는 메소드인 findOne()과 findOneBy()의 차이?
findOne과 findOneBy는 TypeORM에서 제공하는 메소드이다. 설명에 따르면 findOne은 단일 엔티티를 찾을 때 사용되고, findOneBy는 필드 조건에 맞는 단일 엔티티를 찾는데 사용된다고 한다. 하지만 이것만으로는 설명이 좀 부족하다. 두 메소드의 차이가 조금씩 있겠지만...
findOne을 주요 식별자(primary Key, DB에서 제일 첫 번째 레코드일때)에 사용할 경우에는 바로 findOne(id) 혹은 findOne()과 같은 형태로 사용하면 되고, 그렇지 않을 경우에는 구분할 수 있는 조건을 넣어줘야한다. 대체로 where을 넣으면 되지 않을까?
findOneBy는 반드시 필요한 조건과 함께 사용해줘야한다. 마찬가지로 where을 사용하면 되지 않을까 싶다.
DB의 특정 행을 찾는 거라면, findOneBy({ where: 조건 }) 으로 찾는게 아마 더 적합할 듯 싶지만! 자동 완성에서도 더 상위에 노출해주는게 findOne()이다 보니 findOne({ where: 조건 }) 형태에 손이 잘 가는 것 같다... 헤헤... 만약 DB의 첫 번째 레코드가 데이터의 id며, id로 특정 행을 찾는 경우에는 findOne()으로 바로 쓰는 게 좋은 것 같다!
비슷한 메소드인 findOneById()는 이제 더 이상 사용하지 않는 메소드라고 한다! 원래는 findOneBy()가 더 이상 사용하지 않는 메소드인 줄 알았다... 그러면 선임님이 그렇게 해놓았을 리가 없잖아 바보야...
이 아래는 저 간단한 차이점을 찾기까지의 나의 삽질...
평화롭지 않은 개발 일상... 파도처럼 나에게 들이닥치는 nestJS 코드... nsetJS로 CRUD를 구현하고 있던 중이었다. 블로그와 챗GPT의 도움으로 완성된 코드에 자꾸만 빨간 밑줄이 뜨는 것이었따...
// user.service.ts
async updateUser(userId: string, updateUserDto: Partial<User>): Promise<User> {
// 빨간줄이 사라지지 않아...
const user = await this.userRepository.findOne(userId);
if (!user) {
throw new NotFoundException(`아이디 ${userId} 를 찾을 수 없습니다.`);
}
Object.assign(user, updateUserDto);
return await this.userRepository.save(user);
}
바로 이렇게... 심지어 이 코드... 챗GPT가 짜준 코드였다... 나는 혼돈에 빠지고 말았다... 저기에 왜 밑줄이 안 지워지는지 챗GPT에게도 물어봤지만,, 챗GPT 선생님도 알지 못했다... 내가 질문을 개떡같이 해서 그럴수도
내가 샘플로 참고한 선임님의 코드에서는 findOne 대신 findOneBy가 있었다. 그래서 findOne을 findOneBy로 바꿨지만 역시나 빨간줄이 사라지지 않았따... findOne과 findOneBy의 차이가 궁금하고, 어떻게 써야 하는지 궁금해서 자체 설명을 찾아봤다.
findOne(options: FindOneOptions<Entity>): Promise<Entity | null>;
/**
* Finds first entity that matches given where condition.
* If entity was not found in the database - returns null.
*/
findOneBy(where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[]): Promise<Entity | null>;
/**
* Finds first entity that matches given id.
* If entity was not found in the database - returns null.
*
* @deprecated use `findOneBy` method instead in conjunction with `In` operator, for example:
*
* .findOneBy({
* id: 1 // where "id" is your primary column name
* })
*/
findOne은 조건에 맞는 첫 번째 엔티티를 찾는다고 한다. findOneBy는 똑같이 첫 번째 엔티티를 찾는데, id를 통해 찾는다.
이 설명만으로는 무슨 말인지 모르겠어서 블로그와 챗GPT에게 물어봤지만... 여전히 무슨말인지 이해할 수 없었다. 아직 nestJS를 주제로 한 우리나라 블로그 글도 잘 없었다. 챗GPT의 설명도 정의 보기로 살펴본 내용과 크게 다른게 없어서 아리송했다. 이 두 차이를 알아야만이 저 빨간줄을 없앨 수 있을 것 같은데...
nsetJS의 공식문서나 한번 휙휙 살펴보고 있던 중에 힌트를 얻었다! 공식 문서에서는 findOneBy({}) 이런 모양으로 사용중이었다. 그리고 findOne을 이렇게 쓴 것도 있었따!
findOne(id: string): Promise<User> {
return this.userModel.findOne({
where: {
id,
},
});
}
조건이라는게 진짜 DB에서 어떤 조건을 말하는거구나, 싶어서 findOne( {where: { userId }} ) 이렇게쓰니까 빨간 줄이 드디어 사라졌따 ㅠㅠ 감동!
async updateUser(userId: string, updateUserDto: Partial<User>): Promise<User> {
const user = await this.userRepository.findOne( {where: { userId }} );
if (!user) {
throw new NotFoundException(`아이디 ${userId} 를 찾을 수 없습니다.`);
}
Object.assign(user, updateUserDto);
return await this.userRepository.save(user);
}
챗 GPT가 그렇다면 처음에는 왜 findeOne()하고 조건 없이 바로 findeOne(userId)란 코드를 짜주었을까? 생각해보니 챗GPT는 userId라는 엔티티가 첫 번째 엔티티인줄 안 거 같다. 첫 번째 엔티티란건, primary Key 처럼 테이블의 식별자를 말하는 것인가?
챗 GPT 선생님, 감사합니다...
findOne과 findOneBy가 nestJs에서 제공하는 메소드인줄 알았는데, TypeORM이 제공하는 메소드라고한다. 처음부터 TypeORM 공식 문서를 찾아봤으면 이해가 빨랐으려나?
이제 아주 조금 CRUD를 짜는데 익숙해지니까, 세세한 메소드에 대한 이해도도 아주 눈꼽만큼 상승한 것 같다. 대체적으로 나는 findOne()을 where과 함께 쓰는 편이었는데, 어쩌면 findOneBy()가 더 적합한 메소드일 수도 있다.