[mongoose] id와 _id의 차이 (id vs _id, document.id의 type은 왜 any일까?)

raipen·2024년 10월 28일

mongoose에서는 기본적으로 schema를 생성할 때 id와 _id 필드가 생성된다.
이 필드들에 대해 알아보자.

_id

이때 _id 필드의 타입은 mongodb의 ObejctId(처럼 행동하는 것)이다.
model에서 document를 가져와 console log를 찍어보면 다음과 같다.

console.log(await model.findOne().exec());
/*
	{
    	_id: new ObjectId("asdf");
        ...
    }
*/

이 ObjectId 인스턴스는 .toString() 메서드를 통해 24자리 16진수 문자열을 얻을 수 있다.(.toHexString()도 있으나 toString에서 toHexString을 리턴하기 때문에 사실상 같은 값이며, 공식문서에서 toString을 권장함)

id

그런데 위 console.log 결과에서는 _id만 존재하고 id는 존재하지 않는다.
하지만 console.log((await model.findOne().exec().id);를 해보면 id가 string으로 id 값이 나오는데, 이는 id가 document 클래스의 필드가 아닌 Document.prototype.id로 정의되어 있기 때문에 클래스를 console.log 했을때는 표기되지 않았던 것이다. (prototype에 대한 것은 js 문서 참고)

id?: any

typescript를 사용 중이라면, id의 타입을 확인해보면 id?: any로 뜬다. 경험적으로 항상 id는 string인데 진짜 항상 string일까? 그렇다면 왜 any로 떠서 불편하게 만드는 걸까?

일단 https://mongoosejs.com/docs/guide.html#id 에 따르면 id는 항상 string이 맞다.

any인 이유는 mongoose 깃허브 이슈에서 이유를 알 수 있다.
https://github.com/Automattic/mongoose/pull/9773
https://github.com/Automattic/mongoose/pull/10248
https://github.com/Automattic/mongoose/issues/13079
요약하자면, mongoose에서 자동으로 넣어주는 id는 string이지만, 그렇게 사용하지 않고, 임의로 다른 타입의 id를 지정하는 것도 허용되기 때문에 id가 number 일수도 있다.
또한 mongoose에서 document의 타입은 보통 HydratedDocument로 가져오는데 이 타입이 & 로 스키마 클래스와 document 타입을 합치고 있기 때문에, 그냥 any로 둘 수 밖에 없다고 한다. (document에서 {id?:string} 으로 해놨는데 schema에서 {id:number}를 쓰게 되면, &로 합쳐지면서 {id:never}가 되어버림)

결론

우리가 직접 schema에서 다른 id를 선언하지 않고, 일반적으로 mongoose에서 넣어주는 id를 쓰는 경우에는 무조건 해당 schame로 생성된 model로부터 가져온 document의 id는 _id를 .toString() 한 string이 맞다. 그러나 여러 가능성 때문에 any로 선언될 수 밖에 없으니 우리가 id를 사용할때, as string을 붙여서 쓰면 된다.

  • 예제
  async create(userId: Types.ObjectId) {
    const response = await this.postModel.create({
      author: userId,
    });
    return response.id as string;
  }

참고

https://mongoosejs.com/docs/guide.html#id
https://mongoosejs.com/docs/guide.html#_id

1개의 댓글

comment-user-thumbnail
2024년 10월 29일

저번에 언급했던 이슈를 정리했네요!
이거 보니까 이해가 됩니다.
잘 읽고 배우고 가요~

답글 달기