Skip to content

Project 9 More Complex Data Strcuture

Theethawat Savastham edited this page May 23, 2024 · 7 revisions

เราจะนำรถเข็น หรือ Cart ในโปรเจกต์สมมติที่เราสร้างขึ้น สร้างขึ้นเป็น Order ที่จะเก็บไว้บน Database

สร้าง Model และ CRUD ของ Order

  1. สร้าง Model ของ Order โดยมีลิสต์ของ Product และปริมาณเหมือนใน Cart ในกิจกรรมที่แล้ว โดยเข้าไปใน Backend/src/models แล้วสร้างเป็น Order.js โดยสร้างโมเดลที่ประกอบไปด้วย
  • date เก็บวันที่สั่งซื้อ มี Type เป็น Date
  • products เป็น Array ของ Object มีส่วนประกอบเป็น product ที่เก็บ product id และ quantity ที่เก็บจำนวน รูปร่างจะเป็น
  products: [
     {
       product: { type: mongoose.Types.ObjectId, ref: 'Product' },
       quantity: Number,
     },
   ],
เฉลย
const mongoose = require('mongoose');

const Order = new mongoose.Schema(
  {
    date: Date,
    products: [
      {
        product: { type: mongoose.Types.ObjectId, ref: 'Product' },
        quantity: Number,
      },
    ],
  },
  {
    timestamps: true,
  },
);


module.exports = mongoose.model('Order',Order);
  1. สร้าง routes สำหรับ order โดยสร้างในโฟลเดอร์ routes โดยเป็น routes ทั้วไป คล้ายๆ กับ routes ตัวอื่นๆ
เฉลย
const express = require('express');
const Order = require('../models/Order');

const router = express.Router();

router.get('/', async (req, res) => {
  try {
    const results = await Order.find({});
    res.status(200).json({ rows: results });
  } catch (error) {
    res.status(404).json({ err: error });
  }
});
router.get('/:id', async (req, res) => {
  try {
    const result = await Order.findById(req.params.id);
    res.status(200).json(result);
  } catch (error) {
    res.status(404).json({ err: error });
  }
});
router.put('/:id', async (req, res) => {
  try {
    await Order.findByIdAndUpdate(req.params.id, {
      $set: req.body,
    });
    res.json({ success: true });
  } catch (error) {
    res.status(400).json({ err: error });
  }
});
router.post('/', async (req, res) => {
  try {
    const newValue = new Order(req.body);
    await newValue.save({});
    res.json(newValue);
  } catch (error) {
    res.status(401).json({ err: error });
  }
});
router.delete('/:id', async (req, res) => {
  try {
    await Order.findByIdAndDelete(req?.params.id);
    res.status(204).send({ success: true });
  } catch (error) {
    res.status(400).json({ err: error });
  }
});

module.exports = router;
  1. Import เข้าไปในไฟล์ index.js แล้วเขียน routes โยงไปที่ order
router.use('/order', orderRouter);
  1. ทดสอบการเรียน API อาจผ่านทาง Postman หรือ อื่นๆ ว่า API สามารถทำงานได้ถูกต้อง

การสร้าง Order จาก Frontend

ในหน้าของ Frontend ทำการสร้างปุ่มสำหรับการสร้าง Order จากสินค้าใน Cart

  1. สร้างปุ่ม ซื้อสินค้า ขึ้นมา จากนั้นเมื่อกดปุ่ม สร้างฟังก์ชันสำหรับการโยน Payload ไปยัง Backend ในส่วนของฟังก์ชันก่อน Return
  const handlePurchase = () => {}

ในส่วนของ UI

  <Button onClick={() => handlePurchase()}>สั่งซื้อ</Button>
  1. เขียน Function handlePurchase เพื่อส่งข้อมูลผ่าน POST API ไปยัง Backend โดยลองดูให้ key ของเราที่เราจะ POST เข้าไปตรงกับใน Schema ของ Backend เช่น ใน Backend ใช้ products เก็บ Array เราก็ต้องทำอย่างนั้น
เฉลย
const handlePurchase = () => {
    axios
      .post(`${process.env.REACT_APP_API_URL}/order`, {
        products: cart,
        date: new Date(),
      })
      .then(() => {
        alert('สำเร็จ')
      })
      .catch((err) => {
        alert(`Error ${err}`)
      })
  }
3. ลองปรับปรุง Model ให้มีการเก็บข้อมูลต่าง ๆ มากขึ้น เช่น เก็บข้อมูลชื่อลูกค้า เบอร์โทรลูกค้า ต่างๆ ได้ตามต้องการ แล้วใส่ฟอร์มประกอบไปด้วย เพื่อให้ใส่ข้อมูลเหล่านี้ ตามที่ต้องการ
เฉลย ในส่วนของ Backend สามารถที่จะเพิ่มโมเดลได้ตามต้องการ ตัวอย่างไอเดียเข่น
const Order = new mongoose.Schema(
  {
    date: Date,
    products: [
      {
        product: { type: mongoose.Types.ObjectId, ref: 'Product' },
        quantity: Number,
      },
    ],
   customer_name: String,
   tel: String,
  },
  {
    timestamps: true,
  },
);

ส่วนใน Frontend อาจจะใช้ react-hook-form มาช่วยอีกทีได้

   //ส่วนเดิมของโปรแกรม
  import { useForm,Controller } from 'react-hook-form'

  const { control, handleSubmit } = useForm()

  const handlePurchase = (data) => {
    axios
      .post(`${process.env.REACT_APP_API_URL}/order`, {
        ...data,
        products: cart,
        date: new Date(),
      })
      .then(() => {
        alert('สำเร็จ')
      })
      .catch((err) => {
        alert(`Error ${err}`)
      })
  }

ในส่วนของ UI ใน OnClick เอามาใช้ในการ Handle Submit แทน

 <div>สินค้าในตะกร้า</div>
          {_.map(cart, (each, index) => (
            <div>
              {each?.product?.name} ปริมาณ {each?.quantity}
              <Button
                color="danger"
                onClick={() => {
                  cart.splice(index, 1)
                  setCart(cart)
                  setRerender(!rerender)
                }}
              >
                ลบ
              </Button>
            </div>
          ))}
          <Controller
            control={control}
            name="customer_name"
            render={({ field }) => <Input {...field} placeholder="ชื่อลูกค้า" />}
          />
          <Button onClick={handleSubmit(handlePurchase)}>สั่งซื้อ</Button>
        </div>
  1. ทดลองการสร้างหน้ารายการออเดอร์ ซึ่งมีรายการออเดอร์ต่างๆ แสดงอยู่
  2. ทดลองทำหน้าแสดง Detail ของแต่ละออเดอร์ ซึ่งมีการแสดงว่าในแต่ละออเดอร์นั้น มีสินค้าอะไรบ้าง เท่าไหร่บ้าง โดยสามารถใช้การ populate ใน database ใน Backend เพื่อให้ระบบดึงข้อมูลต่าง ๆ ออกมาได้ ไม่ได้ออกมาเพียง ID
เฉลย ใน backend route สำหรับ get one สามารถ populate ตามนี้ได้ ```js router.get('/:id', async (req, res) => { try { const result = await Order.findById(req.params.id).populate( 'products.product', ); res.status(200).json(result); } catch (error) { res.status(404).json({ err: error }); } }); ```

Challenging Problem

ทดลองทำการใส่ Attribute คงเหลือ หรือ ปริมาณ ใน Model ของ Product ที่เราสร้างไว้ต่างแต่แรก โดยอาจจะใช้คำว่า remain, quantity, amount หรือคำอื่นที่สื่อความหมายได้ แล้วเราก็จะสามารถมาแก้ Product เพื่อที่จะอัพเดทประมาณคงคลังได้ โจทย์ในข้อนี้คือ ลองให้เมื่อมีการสร้าง Order แล้ว Backend ของเรา ไปทำการลดจำนวนคงเหลือของ Product ชิ้นนี้ใน Model ของ Product ด้วย และถ้าเป็นไปได้ กรณีสินค้าไหนปริมาณในคลังเหลือ 0 ให้กำหนดให้ปุ่มเพิ่มลงตะกร้าของสินค้าชนิดนั้น ไม่สามารถกดได้

General

Project 1 Familiar with React

Project 2 Tailwind CSS, Component and Layouting

Project 3 useState, useEffect, React Hook and API Call

Project 4 Basic Express, API and Database Access

Project 5 Frontend Backend Integration

Project 6 Routing

Project 7 Search with react

Project 8 Pushing the Array

Project 9 More complex data structure

Project 10 Mongo Aggregate Pipeline

Project 11 Create Pagination and Search

Clone this wiki locally