-
Notifications
You must be signed in to change notification settings - Fork 0
Project 9 More Complex Data Strcuture
เราจะนำรถเข็น หรือ Cart ในโปรเจกต์สมมติที่เราสร้างขึ้น สร้างขึ้นเป็น Order ที่จะเก็บไว้บน Database
- สร้าง 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);- สร้าง 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;- Import เข้าไปในไฟล์ index.js แล้วเขียน routes โยงไปที่ order
router.use('/order', orderRouter);- ทดสอบการเรียน API อาจผ่านทาง Postman หรือ อื่นๆ ว่า API สามารถทำงานได้ถูกต้อง
ในหน้าของ Frontend ทำการสร้างปุ่มสำหรับการสร้าง Order จากสินค้าใน Cart
- สร้างปุ่ม ซื้อสินค้า ขึ้นมา จากนั้นเมื่อกดปุ่ม สร้างฟังก์ชันสำหรับการโยน Payload ไปยัง Backend ในส่วนของฟังก์ชันก่อน Return
const handlePurchase = () => {}ในส่วนของ UI
<Button onClick={() => handlePurchase()}>สั่งซื้อ</Button>- เขียน 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}`)
})
}เฉลย
ในส่วนของ 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>
- ทดลองการสร้างหน้ารายการออเดอร์ ซึ่งมีรายการออเดอร์ต่างๆ แสดงอยู่
- ทดลองทำหน้าแสดง 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 }); } }); ```ทดลองทำการใส่ Attribute คงเหลือ หรือ ปริมาณ ใน Model ของ Product ที่เราสร้างไว้ต่างแต่แรก โดยอาจจะใช้คำว่า remain, quantity, amount หรือคำอื่นที่สื่อความหมายได้ แล้วเราก็จะสามารถมาแก้ Product เพื่อที่จะอัพเดทประมาณคงคลังได้ โจทย์ในข้อนี้คือ ลองให้เมื่อมีการสร้าง Order แล้ว Backend ของเรา ไปทำการลดจำนวนคงเหลือของ Product ชิ้นนี้ใน Model ของ Product ด้วย และถ้าเป็นไปได้ กรณีสินค้าไหนปริมาณในคลังเหลือ 0 ให้กำหนดให้ปุ่มเพิ่มลงตะกร้าของสินค้าชนิดนั้น ไม่สามารถกดได้