질문
사용자 주문 목록 '전체' 조회 (GET /orders)
프론트에 보내줘야 할 데이터 : 주문일자, 배송정보(주소, 수령인), totalPrice, 상품정보(책이름, 개수)
orders테이블에는 => 주문일자, 배송정보(주소, 수령인), totalPrice
orderItems 테이블 => book_id, count 있음
서버에서 최종적으로 보내줘야할 데이터 형식은
{
"id": 19,
"user_id": "bomin",
"adress": "서울 관악구",
"receiver": "김보민",
"created_at": "2025-05-21 19:27:04",
"totalPrice": 14000,
"orderInfos" : [
{"주문한 책 이름1" : "count"},
{"주문한 책 이름2" : "count"}
]
}, 이거 여러개
결론 => orderInfos를 따로 만들어줘야 함
하나의 쿼리로 처리하기 보단, 각 단계를 거쳐서 최종 JSON 형태 데이터를 만들어야 함.
✅ 목표 구조 요약
**orders 1건당 여러 개의 orderItems (도서)**를 포함한 형태로:
[
{
"id": 19,
...
"orderInfo": [
{ "책이름1": count },
{ "책이름2": count }
]
},
...
]
✅ 쿼리 접근 방식 (1회로는 어렵고, 보통 2단계로 처리)
1단계: orders 목록 조회 (기본 주문 정보)
SELECT * FROM orders WHERE user_id = ?;
2단계: 각 주문에 해당하는 orderItems + books JOIN 조회
SELECT order_id, books.title, orderItems.count
FROM orderItems
JOIN books ON orderItems.book_id = books.id
WHERE order_id IN (주문 ID들);
이렇게 하면 아래와 같은 평탄한 형태로 나와:
| order_id | title | count |
| 19 | 책이름1 | 1 |
| 19 | 책이름2 | 2 |
| 20 | 책이름3 | 3 |
| 20 | 책이름4 | 4 |
✅ Node.js에서 최종적으로 이렇게 조립
// 사용자 주문 목록 '전체' 조회 (GET /orders)
// 주문일자, 배송정보(주소, 수령인), totalPrice, 상품정보(책이름, 개수)
async function getAllOrder(req, res) {
const conn = await pool.getConnection();
const {user_id} = req.body
try {
// 1. orders 정보 조회
const [orders] = await conn.query(
`SELECT * FROM orders WHERE user_id = ?`, user_id
)
if(orders.length === 0) {
return res.status(StatusCodes.OK).json(orders)
}
const orderIds = orders.map(value => value.id)
// 2. orderItems + books JOIN 조회
const [orderDetails] = await conn.query(
`SELECT orderItems.order_id, orderItems.count, books.title
FROM orderItems
LEFT JOIN books ON orderItems.book_id = books.id
WHERE orderItems.order_id IN (?)`,
[orderIds]
)
// 3. orders 배열에 orderInfos 구성
// orders는 순회하며 > orders.id랑 orderItems의 order_id랑 일치하는 것만 빼낸다
// 일치하는놈을 만나면 > {title : count} 이것만 구성한다
// 최종적으로 orders정보에 => orderInfos : [{title1 : count}, {title2 : count}] 이렇게 넣는다
const groupedResult = orders.map(order => {
const matchedItems = orderDetails
.filter(detail => detail.order_id === order.id)
.map(matched => {return {[matched.title] : matched.count} })
return {
...order,
orderInfos: matchedItems
}
})
return res.status(StatusCodes.OK).json(groupedResult)
}
catch(err) {
console.error("주문 조회 에러 : ", err)
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).end()
}
}
🔍 추가 팁
- order_id IN (?)에서 orderIds가 빈 배열이면 에러나므로, 길이 체크는 필수야.
- orderInfo 구조를 [{title: count}]으로 만들었는데, 만약 [{title, count}]처럼 일반 배열 형태가 더 낫다고 판단되면 그렇게 바꿔도 돼.
🔚 요약
- 1:N 구조의 데이터는 SQL JOIN만으로 JSON 계층 구조로 만들기 어렵다.
- 보통은 두 번의 쿼리 (1: orders, 2: orderItems + books) 후, JS에서 가공.
- 성능 문제 없고, 응답도 직관적으로 구성 가능.
'mariaDB > 3. SQL 사용법' 카테고리의 다른 글
| mysql. 연결 생성 방식=> createConnection() vs createPool() 차이점 (0) | 2025.05.21 |
|---|---|
| 방금 테이블에 INSERT한 row의 ID를 가져오기 (0) | 2025.05.21 |
| 도서구매사이트 - 주문 API 작성 시 코드 리팩토링 (0) | 2025.05.21 |
| IN (?, ?, ?) 문법 (0) | 2025.05.20 |
| EXISTS 문법 (0) | 2025.05.19 |