SMAIVNN
article thumbnail

더 공부하고 정리한 추가 게시물이 있습니다. 

node.js의 Express와 nestJs에서의 mongoDB find()메서드 차이점

mongoose의 find()메서드를 Express환경에서 사용할 경우 다음과 같이 출력된다.

[
  {
    "_id": "id항목입니다",
    "title": "test2",
    "content": "toDo Contents2",
    "status": true,
    "priority": 0,
    "dueDate": "2024-03-21T00:00:00.000Z",
    "category": "sports",
    "completedDate": "2023-10-25T07:59:36.295Z"
  },
]

반면nestJs에서 find()를 사용할 경우 다음과 같이 메타데이터들이 출력된다.

[
  {
    "$__": {
      "activePaths": {
        "paths": {
          "category": "init",
          "dueDate": "init",
          "content": "init",
          "title": "init",
          "userId": "init",
          "status": "init",
          "priority": "init",
          "isDeleted": "init",
          "_id": "init",
          "createdAt": "init",
          "updatedAt": "init",
          "__v": "init",
          "completedDate": "init"
        },
        "states": {
          "require": {},
          "default": {},
          "init": {
            "_id": true,
            "userId": true,
            "title": true,
            "content": true,
            "status": true,
            "priority": true,
            "dueDate": true,
            "category": true,
            "isDeleted": true,
            "createdAt": true,
            "updatedAt": true,
            "__v": true,
            "completedDate": true
          }
        }
      },
      "skipId": true
    },
    "$isNew": false,
    "_doc": {
      "_id": {},
      "userId": "",
      "title": "test2",
      "content": "toDo Contents2",
      "status": true,
      "priority": 0,
      "dueDate": "2024-03-21T00:00:00.000Z",
      "category": "sports",
      "isDeleted": false,
      "createdAt": "2023-10-25T07:58:51.436Z",
      "updatedAt": "2023-10-25T07:59:36.295Z",
      "__v": 0,
      "completedDate": "2023-10-25T07:59:36.295Z"
    }
  },

둘의 출력이 이렇게 다른 이유는 Express환경에서 Mongoose의 find() 메서드를 사용하면 일반적으로 JSON 형식으로 결과가 반환된다. 이 결과는 기본적으로 JavaScript 객체로 표시된다.

 

하지만 NestJs에서 Mongoose를 사용할 때는 결과 객체가 Mongoose 문서(Document) 객체로 표시된다. 이것이 `$__``_doc`와 같은 필드가 결과 객체에 추가되는 이유이다. Mongoose는 MongoDB문서를 JavaScript객체로 감싸며, 이러한 추가 필드는 Mongoose의 내부 속성을 나타내며, 결과 객체의 실제 데이터는 _doc필드 아래에 저장된다.

 

따라서, nestJs에서 Mongoose결과를 일반적은 JSON형태로 표시하려면 .lean() 메서드를 사용할 수 있다. .lean()은 Mongoose결과를 일반 JavaScript 객체로 변환한다.

const user = await user.find().lean();

하지만 이와 같은 방법을 사용하면 Mongoose가 제공하는 모델 메서드 (예: save() 또는 가상필드)를 사용할 수 없다는 단점이 있다. 

 

그렇다면 데이터를 가공하거나 가상 필드를 사용하고자 한다면 어떻게 하면 될까?

nestJs에서 mongoDB document 가공하는 법

데이터 사후 가공 하기

프로젝트를 진행하며 가장 좋았던 방법은 가상필드를 정의 후 데이터를 사후 가공 하는 것이다. 우선 readOnlyData라는 가상필드를 정의한 후 다음과 같은 방법으로 map() 함수나 다른 함수를 사용하여 결과를 가공한다. 이렇게 필요한 필드만 선택하여 새로운 객체로 만들 수 있다.

  const allUser = await this.userRepository.findAllUser(code);
  const readOnlyData = allUser.map((user) => user.readOnlyData);
  return readOnlyData;

virtual field를 만들 때 objectId가 출력되지 않는 이유

virtual field를 만들 때 _id와 같은 objectId가 출력되지 않을 때가 있다. 이 때는 id를 표기하는 방법에 의해서 그런 것인데. 아래 코드를 보자.

import ...

const options: SchemaOptions = {
  timestamps: true,
};

@Schema(options)
export class Post extends Document {
  
  ...필드...

  readonly readOnlyData: {
    _id: string;
    title: string;
    content: string;
    status: boolean;
    priority: number;
    dueDate: string;
    category: string;
    completedDate: string;
  };
}

const _PostSchema = SchemaFactory.createForClass(Post);

_PostSchema.virtual('readOnlyData').get(function (this: Post) {
  return {
    _id: this.id, // 이 부분을 확인하자
    title: this.title,
    content: this.content,
    status: this.status,
    priority: this.priority,
    dueDate: this.dueDate,
    category: this.category,
    completedDate: this.completedDate,
  };
});

_PostSchema.set('toObject', { virtuals: true });
_PostSchema.set('toJSON', { virtuals: true });

export const PostSchema = _PostSchema;

주석 처리한 부분이 _id: this._id로 되어있을 가능성이 있다.

Mongoose에서는 기본적으로 _id필드는 MongoDB의 기본 식별자인 ObjectId와 연결되어 있다. _id 필드는 명시적으로 정의된 경우에만 사용자 지정 필드 값으로 덮어쓸 수 있다. 따라서 출력이 되지 않는 것이다. this.id는 Mongoose가 문서의 ObjectId를 나타내는 기본적인 방식인데, 따라서 가상필드에서 this.id를 사용하면 현재 문서의 ObjectId를 가져와 _id필드로 반환하며 이로인해 _id가 출력되게 된다.

profile

SMAIVNN

@SMAIVNN

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!