Reka Bentuk Aras Rendah: Sistem Pengundian - Kes Tepi
Jadual kandungan
Kes 1 - Mengendalikan Versi untuk Kemas Kini
Kes 2 - PollID menjadi UUID & bukan Kunci Utama
Kes 3 - Pilihan Kosong atau Tidak Sah
Kes 4 - Pilihan Pendua
Kes 5 - Had Panjang Soalan
Kes 6 - Tamat Pungutan Suara
Sila rujuk artikel berikut terlebih dahulu:
Reka Bentuk Peringkat Rendah: Sistem Pengundian: Asas
Reka Bentuk Peringkat Rendah: Sistem Pengundian - Menggunakan Node.js & SQL
Pengendalian Kes Tepi
Kes 1
Untuk mengurus kemas kini kepada soalan dan pilihan tinjauan pendapat sambil mengekalkan butiran sebelumnya yang dikaitkan dengan ID tinjauan pendapat yang sama, anda boleh melaksanakan sistem versi. Pendekatan ini membolehkan anda menjejaki data sejarah untuk setiap tinjauan pendapat, memastikan butiran lama dikekalkan walaupun selepas kemas kini.
Langkah 1: Perubahan Skema Pangkalan Data
-
Kemas kini Jadual Undian
- Tambahkan lajur current_version_id pada jadual tinjauan pendapat untuk menjejaki versi terbaru tinjauan pendapat.
-
Buat Jadual Versi Pungutan Suara
- Buat jadual baharu untuk menyimpan versi sejarah tinjauan pendapat.
Skema Pangkalan Data dikemas kini
CREATE DATABASE polling_system; USE polling_system; CREATE TABLE polls ( poll_id INT AUTO_INCREMENT PRIMARY KEY, current_version_id INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (current_version_id) REFERENCES poll_versions(version_id) ON DELETE SET NULL ); CREATE TABLE poll_versions ( version_id INT AUTO_INCREMENT PRIMARY KEY, poll_id INT, question VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (poll_id) REFERENCES polls(poll_id) ON DELETE CASCADE ); CREATE TABLE options ( option_id INT AUTO_INCREMENT PRIMARY KEY, poll_id INT, option_text VARCHAR(255) NOT NULL, FOREIGN KEY (poll_id) REFERENCES polls(poll_id) ON DELETE CASCADE ); CREATE TABLE votes ( vote_id INT AUTO_INCREMENT PRIMARY KEY, poll_id INT, user_id VARCHAR(255) NOT NULL, option_id INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (poll_id) REFERENCES polls(poll_id) ON DELETE CASCADE, FOREIGN KEY (option_id) REFERENCES options(option_id) ON DELETE CASCADE );
Langkah 2: Perubahan Pelaksanaan API
Kemas kini Pengawal Undian
Ubah suai kaedah updatePoll untuk menyemak sama ada soalan telah berubah sebelum membuat versi baharu.
Fail: controllers/pollController.js
const pool = require('../db/db'); // Create Poll exports.createPoll = async (req, res) => { const { question, options } = req.body; if (!question || !options || !Array.isArray(options) || options.length < 2) { return res.status(400).json({ message: "Invalid input data. Question and at least two options are required." }); } try { const connection = await pool.getConnection(); await connection.beginTransaction(); const [result] = await connection.execute( 'INSERT INTO polls (current_version_id) VALUES (NULL)' ); const pollId = result.insertId; const [versionResult] = await connection.execute( 'INSERT INTO poll_versions (poll_id, question) VALUES (?, ?)', [pollId, question] ); const versionId = versionResult.insertId; // Update the current version in the polls table await connection.execute( 'UPDATE polls SET current_version_id = ? WHERE poll_id = ?', [versionId, pollId] ); const optionQueries = options.map(option => { return connection.execute( 'INSERT INTO options (poll_id, option_text) VALUES (?, ?)', [pollId, option] ); }); await Promise.all(optionQueries); await connection.commit(); connection.release(); res.status(201).json({ pollId, message: "Poll created successfully." }); } catch (error) { console.error("Error creating poll:", error.message); res.status(500).json({ message: "Error creating poll." }); } }; // Update Poll exports.updatePoll = async (req, res) => { const { pollId } = req.params; const { question, options } = req.body; if (!pollId || !options || !Array.isArray(options) || options.length < 2) { return res.status(400).json({ message: "Invalid input data. At least two options are required." }); } try { const connection = await pool.getConnection(); await connection.beginTransaction(); // Fetch the existing poll const [existingPoll] = await connection.execute( 'SELECT question FROM poll_versions WHERE poll_id = (SELECT current_version_id FROM polls WHERE poll_id = ?)', [pollId] ); if (existingPoll.length === 0) { await connection.rollback(); connection.release(); return res.status(404).json({ message: "Poll not found." }); } const currentQuestion = existingPoll[0].question; // Check if the question has changed if (currentQuestion !== question) { // Create a new version since the question has changed const [versionResult] = await connection.execute( 'INSERT INTO poll_versions (poll_id, question) VALUES (?, ?)', [pollId, question] ); const versionId = versionResult.insertId; // Update the current version in the polls table await connection.execute( 'UPDATE polls SET current_version_id = ? WHERE poll_id = ?', [versionId, pollId] ); } // Remove old options and insert new ones await connection.execute('DELETE FROM options WHERE poll_id = ?', [pollId]); const optionQueries = options.map(option => { return connection.execute( 'INSERT INTO options (poll_id, option_text) VALUES (?, ?)', [pollId, option] ); }); await Promise.all(optionQueries); await connection.commit(); connection.release(); res.status(200).json({ message: "Poll updated successfully." }); } catch (error) { console.error("Error updating poll:", error.message); await connection.rollback(); res.status(500).json({ message: "Error updating poll." }); } }; // Delete Poll exports.deletePoll = async (req, res) => { const { pollId } = req.params; try { const connection = await pool.getConnection(); const [result] = await connection.execute( 'DELETE FROM polls WHERE poll_id = ?', [pollId] ); connection.release(); if (result.affectedRows === 0) { return res.status(404).json({ message: "Poll not found." }); } res.status(200).json({ message: "Poll deleted successfully." }); } catch (error) { console.error("Error deleting poll:", error.message); res.status(500).json({ message: "Error deleting poll." }); } }; // Vote in Poll exports.voteInPoll = async (req, res) => { const { pollId } = req.params; const { userId, option } = req.body; if (!userId || !option) { return res.status(400).json({ message: "User ID and option are required." }); } try { const connection = await pool.getConnection(); const [userVote] = await connection.execute( 'SELECT * FROM votes WHERE poll_id = ? AND user_id = ?', [pollId, userId] ); if (userVote.length > 0) { connection.release(); return res.status(400).json({ message: "User has already voted." }); } const [optionResult] = await connection.execute( 'SELECT option_id FROM options WHERE poll_id = ? AND option_text = ?', [pollId, option] ); if (optionResult.length === 0) { connection.release(); return res.status(404).json({ message: "Option not found." }); } const optionId = optionResult[0].option_id; await connection.execute( 'INSERT INTO votes (poll_id, user_id, option_id) VALUES (?, ?, ?)', [pollId, userId, optionId] ); connection.release(); res.status(200).json({ message: "Vote cast successfully." }); } catch (error) { console.error("Error casting vote:", error.message); res.status(500).json({ message: "Error casting vote." }); } }; // View Poll Results exports.viewPollResults = async (req, res) => { const { pollId } = req.params; try { const connection = await pool.getConnection(); const [poll] = await connection.execute( 'SELECT * FROM polls WHERE poll_id = ?', [pollId] ); if (poll.length === 0) { connection.release(); return res.status(404).json({ message: "Poll not found." }); } const [options] = await connection.execute( 'SELECT option_text, COUNT(votes.option_id) as vote_count FROM options ' + 'LEFT JOIN votes ON options.option_id = votes.option_id ' + 'WHERE options.poll_id = ? GROUP BY options.option_id', [pollId] ); connection.release(); res.status(200).json({ pollId: poll[0].poll_id, question: poll[0].question, results: options.reduce((acc, option) => { acc[option.option_text] = option.vote_count; return acc; }, {}) }); } catch (error) { console.error("Error viewing poll results:", error.message); res.status(500).json({ message: "Error viewing poll results." }); } };
Langkah 3: Kemas kini Laluan Undian
Pastikan laluan ditakrifkan dengan betul dalam pollRoutes.js anda.
Fail: route/pollRoutes.js
const express = require('express'); const router = express.Router(); const pollController = require('../controllers/pollController'); // Routes router.post('/polls', pollController.createPoll); router.put('/polls/:pollId', pollController.updatePoll); router.delete('/polls/:pollId', pollController.deletePoll); router.post('/polls/:pollId/vote', pollController.voteInPoll); router.get('/polls/:pollId/results', pollController.viewPollResults); module.exports = router;
Ringkasan Perubahan
-
Pangkalan Data:
- Mengemas kini jadual tinjauan pendapat untuk memasukkan current_version_id.
- Mencipta jadual poll_versions untuk menjejak versi soalan.
- Jadual pilihan dan undian kekal tidak berubah.
-
API:
- Mencipta kaedah createPoll baharu untuk memulakan tinjauan pendapat dan versi.
- Mengemas kini kaedah updatePoll untuk menyemak perubahan soalan sebelum membuat versi baharu.
- Kaedah tambahan untuk mengundi dan melihat keputusan tinjauan pendapat.
-
Penghalaan:
- Memastikan semua laluan yang diperlukan ditakrifkan untuk mengendalikan penciptaan tinjauan pendapat, kemas kini, pengundian dan keputusan.
Kes 2
Untuk mengendalikan senario di mana pollId diperlukan untuk menjadi UUID (Pengecam Unik Sejagat).
Berikut ialah langkah untuk melaksanakan UUID untuk thepollId dalam sistem pengundian anda tanpa memberikan kod:
Langkah-langkah untuk Melaksanakan UUID untuk ID Tinjauan
-
** Kemas Kini Skema Pangkalan Data:**
- Ubah suai jadual tinjauan pendapat, versi_pungutan suara, pilihan dan undian untuk menggunakan CHAR(36) untuk id_pungutan suara dan bukannya integer.
- Buat jadual poll_versions baharu untuk menyimpan versi sejarah soalan tinjauan pendapat dan pilihan yang dipautkan oleh UUID.
-
** Generasi UUID:**
- Tentukan kaedah untuk menjana UUID. Anda boleh menggunakan perpustakaan atau fungsi terbina dalam dalam persekitaran aplikasi anda untuk mencipta UUID.
-
** Cipta Logik Tinjauan:**
- Apabila membuat tinjauan pendapat baharu, hasilkan UUID dan gunakannya sebagai poll_id.
- Masukkan rekod tinjauan pendapat baharu ke dalam jadual tinjauan pendapat.
- Masukkan soalan awal ke dalam jadual poll_versions dan pautkannya dengan UUID yang dijana.
-
** Kemas kini Logik Undian:**
- Apabila mengemas kini tinjauan pendapat:
-
Semak sama ada soalan telah berubah.
- Jika soalan telah berubah, buat entri versi baharu dalam jadual thepoll_versions untuk menyimpan soalan dan pilihan lama.
- Kemas kini jadual tinjauan pendapat dengan soalan baharu dan pilihan yang perlu.
-
** Logik Pengundian:**
- Kemas kini mekanisme pengundian untuk memastikan ia menggunakan UUID sebagai poll_id.
Sahkan bahawa UUID yang disediakan dalam permintaan undian wujud dalam jadual tinjauan pendapat.
-
** Kemas Kini API:**
- Ubah suai titik akhir API untuk menerima dan mengembalikan UUID untuk poll_id.
- Pastikan semua operasi API (buat, kemas kini, padam, undi) merujuk format UUID secara konsisten.
-
** Ujian:**
- Uji aplikasi dengan teliti untuk memastikan UUID dikendalikan dengan betul dalam semua senario (penciptaan, kemas kini, pengundian dan mendapatkan semula keputusan tinjauan pendapat).
-
** Dokumentasi:**
- Kemas kini dokumentasi API anda untuk mencerminkan perubahan dalam format thepoll_id dan sebarang kelakuan baharu yang berkaitan dengan versi dan penggunaan UUID.
Dengan mengikut langkah ini, anda boleh berjaya melaksanakan UUID untuk pollId dalam sistem pengundian anda sambil memastikan integriti data dan penjejakan sejarah.
Kes 3
Pilihan Kosong atau Tidak Sah
Pendekatan Pengesahan:
- Pengesahan Input API: Laksanakan semakan dalam titik akhir API anda untuk mengesahkan bahawa pilihan yang disediakan dalam kandungan permintaan tidak kosong dan memenuhi kriteria tertentu (cth., tiada aksara khas jika tidak dibenarkan).
- Mekanisme Maklum Balas: Berikan mesej ralat yang jelas kepada pengguna jika pilihan tidak sah atau kosong, membimbing mereka untuk membetulkan input mereka.
Kes 4
Pilihan Pendua
Semakan Keunikan:
- Pengesahan Pra-Sisip: Sebelum menambah pilihan pada tinjauan pendapat, semak pilihan sedia ada dalam pangkalan data untuk pendua. Ini boleh dilakukan dengan menanyakan jadual pilihan menggunakan ID tinjauan pendapat dan membandingkannya dengan pilihan baharu.
- Maklum Balas Pengguna: Jika pilihan pendua dikesan, kembalikan mesej ralat yang bermakna untuk memaklumkan pengguna pilihan yang menjadi pendua, membolehkan mereka mengubah suai input mereka dengan sewajarnya.
Kes 5
Had Panjang Soalan
Had Perwatakan:
- Pengesahan API: Tetapkan had aksara maksimum untuk soalan tinjauan pendapat dan pilihan dalam API anda. Ini boleh dilakukan dengan menyemak panjang soalan dan setiap pilihan semasa proses penciptaan dan kemas kini.
- Maklum Balas Antara Muka Pengguna: Laksanakan pengesahan pihak pelanggan untuk memberikan maklum balas segera kepada pengguna apabila mereka melebihi had aksara semasa menaip, meningkatkan pengalaman pengguna.
Kes 6
Tamat Pungutan Suara
Mekanisme Tamat Tempoh:
- Pengurusan Cap Masa: Tambahkan medan cap masa pada jadual tinjauan pendapat untuk merekodkan apabila setiap tinjauan pendapat dibuat dan secara pilihan medan lain untuk tarikh tamat tempoh.
- Semakan Berjadual: Laksanakan kerja latar belakang atau tugas cron yang menyemak secara berkala untuk tinjauan yang telah tamat tempoh dan menandakannya sebagai tidak aktif dalam pangkalan data. Ini juga boleh termasuk menghalang undian pada tinjauan pendapat yang telah tamat tempoh.
- Pemberitahuan Pengguna: Secara pilihan, maklumkan kepada pencipta tinjauan pendapat dan peserta tentang tarikh tamat tempoh yang akan berlaku, membenarkan mereka terlibat dengan tinjauan pendapat sebelum ia menjadi tidak aktif.
Sila rujuk artikel berikut terlebih dahulu:
Reka Bentuk Peringkat Rendah: Sistem Pengundian: Asas
Reka Bentuk Peringkat Rendah: Sistem Pengundian - Menggunakan Node.js & SQL
Lagi Butiran:
Dapatkan semua artikel berkaitan reka bentuk sistem
Hastag: SystemDesignWithZeeshanAli
reka bentuk sistemdenganzeeshanali
Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli
Atas ialah kandungan terperinci Reka Bentuk Aras Rendah: Sistem Pengundian - Kes Tepi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Stock Market GPT
Penyelidikan pelaburan dikuasakan AI untuk keputusan yang lebih bijak

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Tutorial ini memperkenalkan secara terperinci bagaimana menggunakan JavaScript untuk melaksanakan fungsi penapisan dinamik pelbagai syarat, yang membolehkan pengguna menapis produk berdasarkan pelbagai atribut seperti warna dan saiz. Melalui struktur HTML yang jelas dan contoh kod JavaScript, artikel menunjukkan cara mengendalikan dan atau logik secara fleksibel untuk memenuhi keperluan penapisan pengguna yang kompleks dan memberikan cadangan pengoptimuman.

Anda boleh memilih elemen dengan atribut data dalam JavaScript melalui pemilih atribut CSS, dan gunakan document.QuerySelector () atau document.QuerySelectorAll () kaedah untuk mencapai matlamat ini. 1. Gunakan [data-attribute] untuk memilih elemen dengan atribut data yang ditentukan (sebarang nilai); 2. Gunakan [data-attribute = "nilai"] untuk memilih elemen yang nilai atributnya sesuai; 3. Akses atribut data melalui elemen.dataset, di mana data-us-id sepadan dengan dataset.userid (ganti

Artikel ini bertujuan untuk menyelesaikan masalah yang @pytest.mark.parametrize decorator tidak dapat secara langsung mengendalikan data yang dijana pada runtime apabila menggunakan pytest dan selenium untuk ujian yang didorong data dinamik. Kami akan meneroka batasan pytest.mark.parametrize secara mendalam, dan memperkenalkan secara terperinci bagaimana untuk melaksanakan ujian parameter secara anggun berdasarkan pemerolehan data dinamik selenium melalui Pytest's PYTest_Generate_Tests Hook berfungsi untuk memastikan fleksibiliti dan kecekapan kes ujian.

Artikel ini bertujuan untuk menyelesaikan masalah mengalihkan butang redirect pautan luaran dalam tetingkap pop-up jQuery menyebabkan kesilapan lompat. Apabila pengguna mengklik pelbagai pautan luaran dalam penggantian, butang lompat di pop timbul mungkin selalu menunjuk pada pautan pertama yang diklik. Penyelesaian teras adalah dengan menggunakan kaedah off ('klik') untuk membatalkan pengendali acara lama sebelum setiap mengikat peristiwa baru, memastikan bahawa tingkah laku lompat sentiasa menunjuk kepada URL sasaran terkini, dengan itu mencapai pengalihan pautan yang tepat dan terkawal.

Artikel ini memperincikan bagaimana untuk membina kaunter masa yang tepat menggunakan JavaScript. Kaunter itu bertambah sekali seminit, tetapi hanya berjalan dalam hari kerja pratetap (Isnin hingga Jumaat) dan jam kerja (seperti 6 pagi hingga 8 malam). Ia boleh menjeda kenaikan semasa waktu tidak bekerja tetapi memaparkan nilai semasa dan menetapkan semula secara automatik pada hari pertama setiap bulan, memastikan ketepatan dan fleksibiliti logik pengiraan.

Artikel ini bertujuan untuk menyelesaikan isu-isu yang lebih baik yang dicetuskan oleh Onmouseover dalam aplikasi React. Dengan menggantikan OnMouseOver dengan OnMouseEnter dan digabungkan dengan OnMouseout dengan OnMouseleave, anda boleh mengurangkan komponen yang tidak perlu membuat semula dan meningkatkan prestasi aplikasi, terutamanya apabila berurusan dengan banyak komponen. Artikel ini akan menyediakan kod sampel dan penjelasan terperinci untuk membantu pemaju memahami dan menggunakan teknik pengoptimuman ini.

Useclientwidth/clientheightforvisiblecontentareaincludingpadding; 2.useOffsetWidth/offsetheightfortotalrenderedSizeIncludingContent, danborder;

Artikel ini menerangkan bagaimana skrip JavaScript dapat diakses dengan berkesan dan dimanipulasi apabila ia dimuatkan dan dilaksanakan sebelum penciptaan elemen DOM dalam pembangunan web. Kami akan memperkenalkan tiga strategi teras: secara langsung lulus rujukan elemen melalui nilai pulangan fungsi, menggunakan peristiwa tersuai untuk mencapai komunikasi antara modul, dan menggunakan MutationObserver untuk mendengar perubahan struktur DOM. Kaedah ini dapat membantu pemaju menyelesaikan cabaran antara masa pelaksanaan JavaScript dan pemuatan kandungan dinamik, memastikan skrip dapat mengendalikan unsur-unsur dengan betul, seperti menjadikannya drag-mampu.
