Heim > Web-Frontend > js-Tutorial > Low-Level-Design: Abfragesystem – Randfälle

Low-Level-Design: Abfragesystem – Randfälle

WBOY
Freigeben: 2024-08-31 14:43:33
Original
551 Leute haben es durchsucht

Low-Level Design: Polling System - Edge Cases

Inhaltsverzeichnis

Fall 1 – Versionierung für Aktualisierung behandeln
Fall 2 – PollID als UUID und nicht als Primärschlüssel
Fall 3 – Leere oder ungültige Optionen
Fall 4 – Doppelte Optionen
Fall 5 – Beschränkung der Fragenlänge
Fall 6 – Ablauf der Umfrage

Bitte lesen Sie zuerst die folgenden Artikel:

  1. Low-Level-Design: Abfragesystem: Basic

  2. Low-Level-Design: Abfragesystem – Verwendung von Node.js und SQL

Umgang mit Randfällen

Fall 1

Um Aktualisierungen der Fragen und Optionen einer Umfrage zu verwalten und gleichzeitig die vorherigen Details, die mit derselben Umfrage-ID verknüpft sind, beizubehalten, können Sie ein Versionierungssystem implementieren. Mit diesem Ansatz können Sie die historischen Daten für jede Umfrage verfolgen und sicherstellen, dass alte Details auch nach Aktualisierungen erhalten bleiben.

Schritt 1: Änderungen des Datenbankschemas

  1. Aktualisieren Sie die Umfragetabelle

    • Fügen Sie der Umfragetabelle eine Spalte „current_version_id“ hinzu, um die neueste Version der Umfrage zu verfolgen.
  2. Erstellen Sie die Umfrageversionstabelle

    • Erstellen Sie eine neue Tabelle, um historische Versionen von Umfragen zu speichern.

Aktualisiertes Datenbankschema

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
);
Nach dem Login kopieren

Schritt 2: Änderungen der API-Implementierung

Aktualisieren Sie den Poll Controller

Ändern Sie die updatePoll-Methode, um zu prüfen, ob sich die Frage geändert hat, bevor Sie eine neue Version erstellen.

Datei: 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." });
    }
};
Nach dem Login kopieren

Schritt 3: Poll-Routen aktualisieren

Stellen Sie sicher, dass die Routen in Ihrer pollRoutes.js richtig definiert sind.

Datei: Routen/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;
Nach dem Login kopieren

Zusammenfassung der Änderungen

  1. Datenbank:

    • Die Umfragetabelle wurde aktualisiert und enthält nun die aktuelle_Versions-ID.
    • Erstellte die Tabelle poll_versions zum Verfolgen von Fragenversionen.
    • Die Optionen- und Abstimmungstabellen bleiben unverändert.
  2. API:

    • Eine neue Methode „createPoll“ erstellt, um Umfragen und Versionen zu initialisieren.
    • Die updatePoll-Methode wurde aktualisiert, um vor dem Erstellen einer neuen Version nach Fragenänderungen zu suchen.
    • Methoden zum Abstimmen und Anzeigen von Umfrageergebnissen hinzugefügt.
  3. Weiterleitung:

    • Es wurde sichergestellt, dass alle notwendigen Routen definiert sind, um die Erstellung von Umfragen, Aktualisierungen, Abstimmungen und Ergebnisse zu verarbeiten.

Fall 2

Zur Handhabung eines Szenarios, in dem die pollId eine UUID (Universally Unique Identifier) ​​sein muss.

Hier sind die Schritte zum Implementieren von UUIDs für thepollId in Ihrem Umfragesystem, ohne Code bereitzustellen:

Schritte zum Implementieren der UUID für die Umfrage-ID

  1. ** Aktualisierung des Datenbankschemas:**

    • Ändern Sie die Tabellen „polls“, „poll_versions“, „options“ und „votes“, um CHAR(36) für poll_id anstelle einer Ganzzahl zu verwenden.
    • Erstellen Sie eine neue poll_versions-Tabelle, um historische Versionen von Umfragefragen und -optionen zu speichern, die durch die UUID verknüpft sind.
  2. ** UUID-Generierung:**

    • Entscheiden Sie sich für eine Methode zum Generieren von UUIDs. Sie können eine Bibliothek oder integrierte Funktionen in Ihrer Anwendungsumgebung verwenden, um UUIDs zu erstellen.
  3. ** Umfragelogik erstellen:**

    • Generieren Sie beim Erstellen einer neuen Umfrage eine UUID und verwenden Sie diese als poll_id.
    • Fügen Sie den neuen Umfragedatensatz in die Umfragetabelle ein.
    • Fügen Sie die ursprüngliche Frage in die Tabelle poll_versions ein und verknüpfen Sie sie mit der generierten UUID.
  4. ** Umfragelogik aktualisieren:**

    • Beim Aktualisieren einer Umfrage:
  5. Überprüfen Sie, ob sich die Frage geändert hat.

    • Wenn sich die Frage geändert hat, erstellen Sie einen neuen Versionseintrag in der Tabelle „poll_versions“, um die alte Frage und die alten Optionen zu speichern.
    • Aktualisieren Sie die Umfragetabelle bei Bedarf mit der neuen Frage und den neuen Optionen.
  6. ** Abstimmungslogik:**

    • Aktualisieren Sie den Abstimmungsmechanismus, um sicherzustellen, dass er die UUID als poll_id verwendet.
  7. Bestätigen Sie, dass die in der Abstimmungsanfrage angegebene UUID in der Umfragetabelle vorhanden ist.

  8. ** API-Updates:**

    • API-Endpunkte so ändern, dass sie UUIDs für poll_id akzeptieren und zurückgeben.
    • Stellen Sie sicher, dass alle API-Vorgänge (Erstellen, Aktualisieren, Löschen, Abstimmen) konsistent auf das UUID-Format verweisen.
  9. ** Testen:**

    • Testen Sie die Anwendung gründlich, um sicherzustellen, dass UUIDs in allen Szenarien (Erstellung, Aktualisierungen, Abstimmungen und Abrufen von Umfrageergebnissen) korrekt gehandhabt werden.
  10. ** Dokumentation:**

    • Aktualisieren Sie Ihre API-Dokumentation, um die Änderungen im Format „poll_id“ und alle neuen Verhaltensweisen im Zusammenhang mit der Versionierung und UUID-Nutzung widerzuspiegeln.

Indem Sie diese Schritte befolgen, können Sie UUIDs für pollId erfolgreich in Ihrem Umfragesystem implementieren und gleichzeitig die Datenintegrität und Verlaufsverfolgung sicherstellen.


Fall 3

Leere oder ungültige Optionen

Validierungsansatz:

  • API-Eingabevalidierung: Implementieren Sie Prüfungen in Ihren API-Endpunkten, um zu überprüfen, ob die im Anforderungstext bereitgestellten Optionen nicht leer sind und bestimmte Kriterien erfüllen (z. B. keine Sonderzeichen, wenn nicht zulässig).
  • Feedback-Mechanismus: Geben Sie dem Benutzer klare Fehlermeldungen, wenn die Optionen ungültig oder leer sind, und leiten Sie ihn an, seine Eingabe zu korrigieren.

Fall 4

Duplikatoptionen

Eindeutigkeitsprüfung:

  • Validierung vor dem Einfügen: Bevor Sie Optionen zu einer Umfrage hinzufügen, überprüfen Sie die vorhandenen Optionen in der Datenbank auf Duplikate. Dies kann erreicht werden, indem die Optionstabelle mithilfe der Umfrage-ID abgefragt und mit den neuen Optionen verglichen wird.
  • Benutzer-Feedback: Wenn eine doppelte Option erkannt wird, geben Sie eine aussagekräftige Fehlermeldung zurück, um den Benutzer darüber zu informieren, welche Optionen Duplikate sind, sodass er seine Eingabe entsprechend ändern kann.

Fall 5

Fragenlängenbeschränkung

Zeichenbeschränkung:

  • API-Validierung: Legen Sie eine maximale Zeichenbeschränkung für Umfragefragen und -optionen in Ihrer API fest. Dies kann durch Überprüfen der Länge der Frage und jeder Option während des Erstellungs- und Aktualisierungsprozesses erfolgen.
  • Feedback zur Benutzeroberfläche: Implementieren Sie eine clientseitige Validierung, um Benutzern sofortiges Feedback zu geben, wenn sie beim Tippen die Zeichenbeschränkung überschreiten, und so das Benutzererlebnis zu verbessern.

Fall 6

Ablauf der Umfrage

Ablaufmechanismus:

  • Zeitstempelverwaltung: Fügen Sie der Umfragetabelle ein Zeitstempelfeld hinzu, um aufzuzeichnen, wann jede Umfrage erstellt wird, und optional ein weiteres Feld für das Ablaufdatum.
  • Geplante Prüfungen: Implementieren Sie einen Hintergrundjob oder eine Cron-Aufgabe, die regelmäßig nach abgelaufenen Umfragen sucht und diese in der Datenbank als inaktiv markiert. Dazu kann auch die Verhinderung von Abstimmungen bei abgelaufenen Umfragen gehören.
  • Benutzerbenachrichtigungen: Optional können Sie Umfrageersteller und Teilnehmer über bevorstehende Ablaufdaten benachrichtigen, damit sie an der Umfrage teilnehmen können, bevor sie inaktiv wird.

Bitte lesen Sie zuerst die folgenden Artikel:

  1. Low-Level-Design: Abfragesystem: Basic

  2. Low-Level-Design: Abfragesystem – Verwendung von Node.js und SQL

Weitere Details:

Holen Sie sich alle Artikel zum Thema Systemdesign
Hastag: SystemDesignWithZeeshanAli

systemdesignwithzeeshanali

Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli

Das obige ist der detaillierte Inhalt vonLow-Level-Design: Abfragesystem – Randfälle. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage