Node.js 1주차 개인과제 트러블 슈팅
1 . 게시글 작성 api
- post 요청으로 게시판에 데이터를 삽입 하는 코드를 작성하였다.
//1. 게시글 작성 api
router.post("/posts", async (req, res) => {
//입력받은 데이터 값을 req.body에 저장
const { user, password, title, content, createdAt } = req.body
console.log(req.body)
// 클라이언트가 요청한 데이터가 없을 때
if ((!user || !password || !title || !content) || null) {
res.status(400).json({ message: "요청한 데이터가 없습니다." })
return
}
try {
//몽고db에 생성할 스키마
const createdPosts = await Posts.create({ user, password, title, createdAt, content })
res.status(200).json({ "message": "게시글을 생성하였습니다." })
} catch (error) {
// 에러 처리
res.status(500).json(`{ ${error}, message: "서버 에러가 발생했습니다." }`)
}
})
오류 내용
- 데이터를 받아오는 부분까지는 무난하게 작성 하였으나 조건문을 작성할때 조건문이 실행되지 않아 여러 방법으로 시도
해보았다 처음에 작성한 조건문은 if문의 조건이 실행되지 않아서
if (!user || !password || !title || !content) {
return res.status(400).json({ message: "데이터 형식이 올바르지 않습니다." });
}
res.status(200).json({ "message": "게시글을 생성하였습니다.", data: createdPosts })
if ((!user || !password || !title || !content) || null) {
res.status(400).json({ message: "요청한 데이터가 없습니다." })
return
}
try {
//몽고db에 생성할 스키마
const createdPosts = await Posts.create({ user, password, title, createdAt, content })
res.status(200).json({ "message": "게시글을 생성하였습니다." })
} catch (error) {
// 에러 처리
res.status(500).json(`{ ${error}, message: "서버 에러가 발생했습니다." }`)
}
2. 게시글 조회 api
- 게시글 조회 api는 입력 받은 데이터를 get요청으로 데이터 전체를 가져오는 코드를 작성했다.
//2. 게시글 조회 api
router.get('/posts', async (req, res) => {
const _data = await Posts.find({})
//_id => postId
const data = _data.map((item) => {
return {
postId: item._id,
user: item.user,
password: item.password,
title: item.title,
content: item.content,
createdAt: item.createdAt,
_id: undefined
};
});
res.json({ data })
})
- 한가지 문제점은 데이터가 입력될때 몽고db에서 자체적으로 primary key를 생성하여 고유한 key값을 _id에 부여 해주는 부분이었다 _id 값을 바꾸기위해 여러가지 방법을 시도해봤다.
첫번째 시도한 방법
- 객체의 특정 key값을 새로운 key값으로 변경해주는 코드를 가져와 변형하여 map 메서드로 사용해보려고 했으나
생각한대로 코드를 작성하지 못하였다.
const obj = { _id: 'value' };
//obj['new key'] = obj['old key']
obj['postId'] = obj['_id'];
delete obj['_id'];
console.log(obj); // { newKey: 'value' }
두번째 시도한 방법
- map함수로 data라는 객체에 접근해 각 요소를 돌며 key 값을 바꿔주려고 했으나 e.id는 객체의 value 값에 접근하는 코드여서 이 방법도 적용하지 못했다.
data.map((e) => delete Object.assign(e, { _postId: e._id })['_id']);
세번째 시도한 방법
- forEach 반복문으로 객체를 돌면서 새로운 key를 할당하려고 햇으나 db변수를 선언하고 사용했어야해서 db변수 선언 방법을 찾지 못해 사용하지 못했다.
var cursor = db.testcoll.find()
cursor.forEach(function (item) {
var oldid = item._id; // we save old _id to use for removal below.
delete item._id; // When we add an item without _id, Mongo creates a unique _id.
db.testcoll.insert(item); // We add item without _id.
db.testcoll.remove(oldid); // We delete the item with bad _id.
});
해결방법
- 변수 data에는 현재 데이터의 모든 값이 들어가 있는 배열이다. 이 배열을 map 메서드로 요소(item) key _id의 값을 postId 변경 해주는 방법을 사용하였다. postId를 제외한 나머지 요소의 key 값은 변경하지 않고 그대로 사용하였으나 새로운 배열에 똑같은 데이터를 넣어줘야 하기때문에 item.'key' 를 입력해줘서 모든 value 값을 넣어주어 해결 하였다
- 이렇게 사용한 방법은 몽고db의 고유한 pk값을 임시로 변경하여 사용하는 것이기 때문에 해당 요청을 제외한 나머지 get요청에서는 _id 값이 그대로 들어온다. 그래서 pk를 변경하고 싶은 요청안에서 다시 반복문을 돌며 pk값을 postId로 변경해주거나 버츄얼 형식으로 변경하는 방법도 있다고 들었으나 시도는 해보지 않았다.
const data = _data.map((item) => {
return {
postId: item._id,
user: item.user,
password: item.password,
title: item.title,
content: item.content,
createdAt: item.createdAt,
_id: undefined
};
});
3. 게시글 상세 조회
- 상세조회 api에서는 :_postId 에 입력된 파라미터 값과 db에 저장된 _id값이 일치하는 데이터를 받아오는 코드를 작성하였다. 변수 {_postId} 에는 파라마터로 들어온 값을 아래와 같이 할당하고
{ _postId : 643d3e1bf69c95415eacdf83 }
구조분해할당 하여 key 값만 할당하였다
const { _postId } = req.params //
- 상세조회 api에서도 게시글 api와 마찬가지로 get요청으로 데이터를 불러오고 불러온 데이터를 변수 _data에 할당한후,
변수 data 에 할당된 배열을 map 메서드를 사용해 _id key값을 postId값으로 변경해주는 작업을 하였다(아마 반복문을 따로 함수로 만들어서 _id를 postId로 변경해주는 함수를 만들고 필요한 부분마다 실행시켰다면 조금더 편할 수 도 있었겠다는 생각도 들었다.)
//3. 게시글 상세 조회
router.get("/posts/:_postId", async (req, res) => {
const { _postId } = req.params
let _data = await Posts.find({})
//_id => postId
let data = _data.map((item) => {
return {
postId: item._id,
user: item.user,
password: item.password,
title: item.title,
content: item.content,
createdAt: item.createdAt,
_id: undefined
};
});
try {
const [result] = data.filter((item) => _postId === String(item.postId))
res.status(200).json({ "data": result })
} catch (err) {
res.status(400).json({ message: '데이터 형식이 올바르지 않습니다.' })
}
})
- try catch 문으로 에러 분기를나누어 에러 처리를 해주었다.
4. 게시글 수정 api
- 게시글 수정 api는 입력된 put메서드를 사용해 입력된 params에 해당하는 _id 값을 db에서 가져와 변수 post에 할당 해주었다 body에 입력받은 데이터는 각각 password, title, content에 할당해 주었다.
입력데이터
{
"password": "5555",
"title": "안녕하세요123421342",
"content": "안녕하세요 342423content 입니다."
}
구조분해로 각각 변수에 req.body로 입력된 값을 할당 해주었다.
password = "5555"
title: "안녕하세요123421342",
content: "안녕하세요 342423content 입니다."
- findOne에서 key값 잘못입력.
let post = await Posts.findOne({ postId: _postId })
- 처음에 db에서 _id의 값을 가져 올때아래와 같은 코드로 작성을 했었다. 하지만 db에는 _id라는 키값만 저장되어 있었기때문에 _id로 수정후 db에서 값을 받아왔다.
// 4. 게시글 수정
router.put("/posts/:_postId", async (req, res) => {
const { _postId } = req.params
const { password, title, content } = req.body
let post = await Posts.findOne({ _id: _postId })
if (Number(password) === post.password) {
console.log(password)
await Posts.updateOne({ _id: _postId }, { $set: { title: title, content: content } })
}
res.status(200).json({ "message": "게시글을 수정하였습니다." })
})
- 조건문식은 처음에 _postId 값과 post.postId의 값을 비교하여 id값이 같은걸 가져오려고 하려고 의도 했으나 이 터무니없는 조건식은 db에는 postId 값이라는 key가 없어서 조건이 false로 되어 아래 식이 실행되지 않았다 애초에 id의 key값에 접근하는 방식이 잘못됐다는 조언을 듣고 입력된 password 값과 db에 입력된 password 값을 비교하여 입력받은 params와
db에 저장된 _id 값이 같은 데이터에서 password가 같은지 비교하고 password 가 같다면 입력받은 데이터로 변경하는 코드를 작성하였다.
await Posts.updateOne({ _id: _postId }, { $set: { title: title, content: content } })
아래와 같은 형식으로 updateOne 메서드를 사용하여 db에 저장된 값을 변경해주었다. updateMany라는 메서드도 있었는데 어떤 차이가 있는지 좀 더 찾아보면 좋을것 같다.
Model이름.updateOne({ 변경하려는 데이터 id }, { $set: { 변경데이터키: 변경데이터 밸류, 변경데이터키: 변경데이터 밸류} })
5. 게시글 삭제 api
- 게시글 수정 api는 게시글 수정 api에서 메서드한개만 바꾸어 똑같은 내용으로 작성하였다.
await Posts.updateOne({ _id: _postId }, { $set: { title: title, content: content } })
- _id: _postId 와 일치하는 params의 값을 db에서 삭제하기위해 deleteOne 메서드를 사용하였다.
await Posts.deleteOne({ _id: _postId })
- 조건문에서 입력받은 데이터의 값 password 와 db에 저장된 password의 값이 일치할때 db에서 데이터를 삭제하는 조건문을 작성했다.
// 5. 게시글 삭제
router.delete("/posts/:_postId", async (req, res) => {
const { _postId } = req.params
const { password } = req.body
let post = await Posts.findOne({ _id: _postId })
if (Number(password) === post.password) {
console.log(password)
await Posts.deleteOne({ _id: _postId })
}
res.status(200).json({ "message": "게시글을 수정하였습니다." })
})
- 처음에 조건문을 실행하지 못해서 각 입력된 값과 db에 저장된 값을 비교해보니 입력된 password 값은 string이었고, db에 저장된 값은 Number로 저장되어 있어서 타입이 달라 조건문을 실행하지 못했다 이를 해결하지 위해 입력된 password값을 Number속성으로 형변환 하여 비교하였다.
- 다른 해결방법으로는 처음 데이터를 입력할때 password의 타입이 Number가 아닐때 오류처리를 하여 Number 타입만 입력 받을 수 있도록 하는 방법도 괜찮을것 같다는 생각이들었다.
오늘 알게된점
- 조건문이 실행되지 않을때는 조건문 안에 console.log 아무 값을 입력하여 조건식이 실행되고 있는지 아닌지를 판단하고 조건식이 실행되지 않을때 조건식을 수정해가며 true일때로 조정해야함.
- 입력된 데이터의 타입과 db에 저장된 데이터 타입이 어떤지 파악해야함.
- db에서 받아온 데이터의 형태가 객체인지 , 배열인지 파악하고 어떤 값을 가져올것인지 파악해야함. 데이터 전체를 조회 할때는 배열 형태로 가져와짐 가져와진 배열을 어떻게 조작할 것인지, 객체의 value에 어떻게 접근할 것인지 자세하게 파악해야함.
- 몽구스의 데이터 조작 함수사용방법과 mongodb에서 함수 사용 형식이 다르기 때문에 함수사용 형식이나 방법도 잘알아야함
- 값이 여러개 들어왔을때 구조분해할당으로 어떤방식으로데이터가 저장되는지 파악해야함.