Conception de bas niveau : système d'interrogation - Cas extrêmes
Table des matières
Cas 1 – Gérer la gestion des versions pour la mise à jour
Cas 2 - PollID doit être comme UUID et non comme clé primaire
Cas 3 - Options vides ou invalides
Cas 4 - Options de duplication
Cas 5 - Limite de longueur des questions
Cas 6 - Expiration du sondage
Veuillez vous référer d'abord aux articles suivants :
Conception de bas niveau : système d'interrogation : de base
Conception de bas niveau : système de sondage - Utilisation de Node.js et SQL
Traitement des cas extrêmes
Cas 1
Pour gérer les mises à jour de la question et des options d'un sondage tout en conservant les détails précédents associés au même identifiant de sondage, vous pouvez implémenter un système de versionnage. Cette approche vous permet de garder une trace des données historiques pour chaque sondage, garantissant ainsi que les anciens détails sont préservés même après les mises à jour.
Étape 1 : Modifications du schéma de base de données
-
Mettre à jour le tableau des sondages
- Ajoutez une colonne current_version_id à la table des sondages pour suivre la dernière version du sondage.
-
Créer le tableau des versions de sondage
- Créez un nouveau tableau pour stocker les versions historiques des sondages.
Schéma de base de données mis à jour
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 );
Étape 2 : Modifications de la mise en œuvre de l'API
Mettre à jour le contrôleur de sondage
Modifiez la méthode updatePoll pour vérifier si la question a changé avant de créer une nouvelle version.
Fichier : 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." }); } };
Étape 3 : Mettre à jour les itinéraires de sondage
Assurez-vous que les itinéraires sont correctement définis dans votre pollRoutes.js.
Fichier : routes/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;
Résumé des modifications
-
Base de données :
- Mise à jour du tableau des sondages pour inclure current_version_id.
- Création de la table poll_versions pour suivre les versions des questions.
- Les tableaux d'options et de votes restent inchangés.
-
API :
- Création d'une nouvelle méthode createPoll pour initialiser les sondages et les versions.
- Mise à jour de la méthode updatePoll pour vérifier les modifications apportées aux questions avant de créer une nouvelle version.
- Ajout de méthodes pour voter et afficher les résultats du sondage.
-
Routage :
- Veiller à ce que tous les itinéraires nécessaires soient définis pour gérer la création, les mises à jour, le vote et les résultats des sondages.
Cas 2
Pour gérer un scénario dans lequel le pollId doit être un UUID (Universally Unique Identifier).
Voici les étapes pour implémenter les UUID pour thepollId dans votre système de sondage sans fournir de code :
Étapes pour implémenter l'UUID pour l'ID de sondage
-
** Mise à jour du schéma de base de données :**
- Modifiez les tables polls, poll_versions, options et votes pour utiliser CHAR(36) pour poll_id au lieu d'un entier.
- Créez une nouvelle table poll_versions pour stocker les versions historiques des questions et options de sondage liées par l'UUID.
-
** Génération UUID :**
- Décidez d'une méthode de génération d'UUID. Vous pouvez utiliser une bibliothèque ou des fonctions intégrées dans votre environnement d'application pour créer des UUID.
-
** Créer une logique de sondage :**
- Lors de la création d'un nouveau sondage, générez un UUID et utilisez-le comme poll_id.
- Insérez le nouvel enregistrement de sondage dans le tableau des sondages.
- Insérez la question initiale dans la table poll_versions et liez-la à l'UUID généré.
-
** Mettre à jour la logique du sondage :**
- Lors de la mise à jour d'un sondage :
-
Vérifiez si la question a changé.
- Si la question a changé, créez une nouvelle entrée de version dans la table poll_versions pour stocker l'ancienne question et les options.
- Mettez à jour le tableau des sondages avec la nouvelle question et les nouvelles options si nécessaire.
-
** Logique de vote :**
- Mettez à jour le mécanisme de vote pour vous assurer qu'il utilise l'UUID comme poll_id.
Vérifiez que l'UUID fourni dans la demande de vote existe dans le tableau des sondages.
-
** Mises à jour de l'API :**
- Modifiez les points de terminaison de l'API pour accepter et renvoyer les UUID pour poll_id.
- Assurez-vous que toutes les opérations de l'API (créer, mettre à jour, supprimer, voter) font référence au format UUID de manière cohérente.
-
** Test :**
- Testez minutieusement l'application pour vous assurer que les UUID sont gérés correctement dans tous les scénarios (création, mises à jour, vote et récupération des résultats du sondage).
-
**Documentations :**
- Mettez à jour la documentation de votre API pour refléter les modifications apportées au format poll_id et tout nouveau comportement lié au contrôle de version et à l'utilisation de l'UUID.
En suivant ces étapes, vous pouvez implémenter avec succès les UUID pour pollId dans votre système de sondage tout en garantissant l'intégrité des données et le suivi historique.
Cas 3
Options vides ou invalides
Approche de validation :
- Validation des entrées API : Mettez en œuvre des vérifications dans vos points de terminaison d'API pour vérifier que les options fournies dans le corps de la demande ne sont pas vides et répondent à des critères spécifiques (par exemple, aucun caractère spécial s'il n'est pas autorisé).
- Mécanisme de rétroaction : Fournissez des messages d'erreur clairs à l'utilisateur si les options sont invalides ou vides, en le guidant pour corriger sa saisie.
Cas 4
Options de duplication
Contrôle d'unicité :
- Validation pré-insertion : Avant d'ajouter des options à un sondage, vérifiez les options existantes dans la base de données pour les doublons. Cela peut être fait en interrogeant la table d'options à l'aide de l'ID du sondage et en la comparant aux nouvelles options.
- Commentaires de l'utilisateur : Si une option en double est détectée, renvoie un message d'erreur significatif pour informer l'utilisateur quelles options sont des doublons, lui permettant ainsi de modifier sa saisie en conséquence.
Cas 5
Limite de longueur des questions
Limitation des caractères :
- Validation de l'API : Définissez une limite maximale de caractères pour les questions et les options de sondage au sein de votre API. Cela peut être fait en vérifiant la longueur de la question et chaque option lors des processus de création et de mise à jour.
- Commentaires sur l'interface utilisateur : Implémentez la validation côté client pour fournir un retour instantané aux utilisateurs lorsqu'ils dépassent la limite de caractères lors de la saisie, améliorant ainsi l'expérience utilisateur.
Cas 6
Expiration du sondage
Mécanisme d'expiration :
- Gestion de l'horodatage : Ajoutez un champ d'horodatage à la table des sondages pour enregistrer la date de création de chaque sondage et éventuellement un autre champ pour la date d'expiration.
- Vérifications programmées : Implémentez un travail en arrière-plan ou une tâche cron qui vérifie périodiquement les sondages expirés et les marque comme inactifs dans la base de données. Cela peut également inclure l’interdiction des votes sur les sondages expirés.
- Notifications utilisateur : Vous pouvez éventuellement informer les créateurs du sondage et les participants des dates d'expiration imminentes, leur permettant ainsi de participer au sondage avant qu'il ne devienne inactif.
Veuillez vous référer d'abord aux articles suivants :
Conception de bas niveau : système d'interrogation : de base
Conception de bas niveau : système de sondage - Utilisation de Node.js et SQL
Plus de détails :
Obtenez tous les articles liés à la conception de systèmes
Hastag : SystemDesignWithZeeshanAli
conception du système aveczeeshanali
Git : https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Stock Market GPT
Recherche d'investissement basée sur l'IA pour des décisions plus intelligentes

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds



Vous pouvez sélectionner des éléments avec des attributs de données dans JavaScript via le sélecteur d'attribut CSS et utiliser la méthode document.QuerySelector () ou document.QuerySelectorAll () pour y parvenir. 1. Utiliser [Data-Attribute] pour sélectionner un élément avec l'attribut de données spécifié (n'importe quelle valeur); 2. Utilisez [data-attribut = "Value"] pour sélectionner un élément dont la valeur d'attribut correspond exactement; 3. Accédez à l'attribut de données via Element.Dataset, où Data-User-ID correspond à DataSet.Userid (Remplacer

Cet article vise à résoudre le problème selon lequel le décorateur de @ pytest.mark.Marametrise ne peut pas gérer directement les données générées lors de l'exécution lors de l'utilisation de PyTest et du sélénium pour des tests dynamiques basés sur les données. Nous explorerons les limites de pytest.mark.Parametrize en profondeur et introduirons en détail comment implémenter gracieusement les tests paramétrés en fonction de l'acquisition de données dynamiques de sélénium via la fonction de crochet Pytest_GenEReate_tests de Pytest pour assurer la flexibilité et l'efficacité des cas de test.

Cet article vise à résoudre le problème de la redirection du bouton de redirection de liaison externe dans la fenêtre pop-up jQuery provoquant des erreurs de saut. Lorsqu'un utilisateur clique sur plusieurs liens externes successivement, le bouton Jump dans la fenêtre contextuelle peut toujours pointer vers le premier lien cliqué. La solution principale consiste à utiliser la méthode OFF ('Click') pour annuler l'ancien gestionnaire d'événements avant chaque liaison d'un nouvel événement, garantissant que le comportement de saut pointe toujours vers l'URL cible, réalisant ainsi une redirection de liens précise et contrôlable.

Cet article détaille comment créer un compteur de synchronisation précis à l'aide de JavaScript. Le comptoir est incrémenté une fois par minute, mais ne se déroule que dans les jours ouvrables prédéfinis (du lundi au vendredi) et les heures de travail (comme 6 h à 20 h). Il peut interrompre les incréments pendant les heures de travail, mais afficher la valeur actuelle et réinitialiser automatiquement le premier jour de chaque mois, assurant la précision et la flexibilité de la logique de comptage.

Cet article explore comment les scripts JavaScript peuvent être effectivement accessibles et manipulés lorsqu'ils sont chargés et exécutés avant la création d'éléments DOM dans le développement Web. Nous présenterons trois stratégies de base: passer directement les références d'élément via des valeurs de retour de fonction, en utilisant des événements personnalisés pour réaliser une communication intermodule et en utilisant MutationObserver pour écouter les changements de structure DOM. Ces méthodes peuvent aider les développeurs à résoudre les défis entre le synchronisation de l'exécution JavaScript et le chargement dynamique du contenu, garantissant que le script peut fonctionner correctement des éléments ajoutés par la suite, tels que les rendre glisserables.

ES2023 a introduit un certain nombre de mises à jour pratiques, marquant l'évolution mature de JavaScript. 1.Array.prototype.Findlast () et FindLasTindex () Les méthodes prennent en charge la recherche à partir de la fin du tableau, améliorant l'efficacité des journaux ou configurations de traitement; 2.Hashbang Syntax (#! / Usr / bin / envNode) permet d'exécuter les fichiers JavaScript directement dans des systèmes de type Unix; 3.Error.Cause prend en charge les chaînes d'erreur, améliorant les capacités de débogage des exceptions; 4. Les spécifications des faibles et des ensembles améliorent la cohérence des moteurs transversales; À l'avenir, les décorateurs (stade3), les disques et les tuples (

UsedotNotationToupDateProperties dans les noms de connaissances; 2.UsebracketnotationfordynAmicorSpecialCharacterPropertyNames; 3.UseObject.assign () ToupdateMultiplepropertiesormergeObjects, notedingitMutatestheoriginalSanempyObjectisSusedArfirStargUment; 4.usethesppyples

Ce tutoriel explique en détail comment formater les numéros en chaînes avec deux décimales fixes en JavaScript, même les entiers peuvent être affichés sous la forme de "# .00". Nous nous concentrerons sur l'utilisation de la méthode numéro.prototype.tofixed (), y compris sa syntaxe, sa fonctionnalité, son exemple de code et des points clés à noter, comme son type de retour étant toujours une chaîne.
