mariaDB/3. SQL 사용법

도서구매사이트 - 주문목록 조회

bbomkim 2025. 5. 24. 19:07

질문

사용자 주문 목록 '전체' 조회 (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에서 가공.
  • 성능 문제 없고, 응답도 직관적으로 구성 가능.