![]
빠르고 간단하게 API를 개발할 때는 Node.js + Express.js + mongoDB
조합을 많이 사용하는 편이다. 추가로 mongoDB ODM(Object Document Mapping)인 mongoose
를 활용해 DB를 관리한다.
mongoose를 이용해서 데이터를 조회한 후 해당 데이터를 json 형태로 변환해서 바로 response를 보낼 때에는 별 문제가 없지만, 해당 데이터를 spread operator로 분해하거나 unit 테스트할 때 종종 원치않는 데이터가 포함된 것을 확인할 수 있다.
{
"name": "hodoopapa",
"position": "개발자",
"roles": [
"ADMIN"
]
}
{
"$__": {
"$options": {
"defaults": true
},
"$setCalled": {},
// ... (생략)
"backup": {
"activePaths": {
"default": {
"_id": true
},
"modify": {
"name": true,
"position": true,
"roles": true
}
}
},
"cachedRequired": {},
// ... (생략)
"getters": {},
"inserting": true,
"pathsToScopes": {
"roles": "[Circular reference found] Truncated by IDE"
},
"session": null,
"strictMode": true,
"validating": null,
"wasPopulated": false
},
"$locals": {},
"$op": null,
"_doc": {
"__v": 0,
"_id": "[Circular reference found] Truncated by IDE",
"name": "hodoopapa",
"position": "개발자",
"roles": [
"ADMIN"
]
},
"isNew": false
}
mongoose Query를 통해서 조회된 데이터는 단순한 Plain Old JavaScript Object(POJO)가 아닌 Mongoose Document형태이기 때문이다.
Mongoose Document는 아래와 같은 것들을 포함하고 있다.
추가 정보와 메서드들을 포함하고 있기 때문에 Query 결과 값을 가지고 수정한 후 save()
메서드를 통해서 수정된 내용을 DB에 반영할 수 있는 것이다.
const findAndUpdateName = async (oldName, newName) => {
const user = await User.findOne({ name: oldName });
user.name = newName;
const savedUser = await user.save();
return savedUser;
다른 정보나 메서드를 사용하지 않는다면 굳이 Mongoose Document를 사용할 필요가 없다. 그래서 보통 toObject()
메서드를 사용해 POJO로 변환해 사용하곤 한다.
이보다 조금 더 효율적인 메서드가 있는데 그것은 lean()
메서드이다.
toObject()
메서드를 이용하는 경우 Query 결과를 Mongoose Document로 만들기 위한 과정을 거쳤다가 다시 POJO로 변환되는 반면, lean()
메서드를 이용할 경우 중간 과정 없이 바로 POJO를 반환한다.
const findbyName = async (name) => {
const user = await User.findOne({ name });
return user.toObject();
};
const findByName = async (name) => {
const user = await User.findOne({ name }).lean();
return user;
};
lean()
메서를 이용해서 얻은 데이터는 Mongoose Document가 아니기 때문에 추가정보나 save()와 같은 메서드들은 사용이 불가능하다. 그래서 아래와 같은 경우 사용을 권장한다.