目次
ケース 1 - 更新のためのバージョニングの処理
ケース 2 - PollID を主キーではなく UUID として使用する
ケース 3 - 空または無効なオプション
ケース 4 - オプションの重複
ケース 5 - 質問の長さの制限
ケース 6 - 投票の有効期限
まず次の記事を参照してください:
低レベル設計: ポーリング システム: 基本
低レベル設計: ポーリング システム - Node.js と SQL の使用
エッジケースの処理
ケース1
同じ投票 ID に関連付けられた以前の詳細を保持しながら、投票の質問とオプションの更新を管理するには、バージョン管理システムを実装できます。このアプローチにより、各投票の履歴データを追跡し、更新後も古い詳細が確実に保持されるようにすることができます。
ステップ 1: データベース スキーマの変更
-
投票表を更新します
- 最新バージョンの投票を追跡するには、current_version_id 列を投票テーブルに追加します。
-
ポーリングバージョンテーブルを作成します
- 投票の履歴バージョンを保存する新しいテーブルを作成します。
更新されたデータベーススキーマ
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 );
ステップ 2: API 実装の変更
ポーリングコントローラーを更新する
新しいバージョンを作成する前に、質問が変更されたかどうかを確認するために updatePoll メソッドを変更します。
ファイル: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 { 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 { 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." }); } };
ステップ 3: ポーリング ルートを更新する
pollRoutes.js でルートが適切に定義されていることを確認してください。
ファイル: ルート/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;
変更の概要
-
データベース:
- current_version_id を含めるために投票テーブルを更新しました。
- 質問のバージョンを追跡するために、poll_versions テーブルを作成しました。
- オプションと投票テーブルは変更されません。
-
API:
- 投票とバージョンを初期化するための新しい createPoll メソッドを作成しました。
- 新しいバージョンを作成する前に質問の変更をチェックするために updatePoll メソッドを更新しました。
- 投票および投票結果の表示方法を追加しました。
-
ルーティング:
- 投票の作成、更新、投票、結果を処理するために必要なルートがすべて定義されていることを確認しました。
ケース2
pollId が UUID (Universally Unique Identifier) である必要があるシナリオを処理します。
コードを提供せずにポーリング システムに thepollId の UUID を実装する手順は次のとおりです。
ポーリング ID の UUID を実装する手順
-
** データベース スキーマの更新:**
- polls、poll_versions、options、votes テーブルを変更して、poll_id に整数ではなく CHAR(36) を使用します。
- UUID によってリンクされたアンケートの質問とオプションの履歴バージョンを保存する新しい poll_versions テーブルを作成します。
-
** UUID 生成:**
- UUID を生成する方法を決定します。UUID を作成するには、アプリケーション環境のライブラリまたは組み込み関数を使用できます。
-
** ポーリング ロジックの作成:**
- 新しい投票を作成するときは、UUID を生成し、それを poll_id として使用します。
- 新しい投票レコードを投票テーブルに挿入します。
- 最初の質問をpoll_versionsテーブルに挿入し、生成されたUUIDにリンクします。
-
** 投票ロジックの更新:**
- アンケートを更新する場合:
-
質問が変更されたかどうかを確認してください。
- 質問が変更された場合は、poll_versions テーブルに新しいバージョンのエントリを作成して、古い質問とオプションを保存します。
- 必要に応じて、新しい質問とオプションを使用して投票表を更新します。
-
** 投票ロジック:**
- 投票メカニズムを更新して、poll_id として UUID を使用するようにします。
投票リクエストで指定された UUID が投票テーブルに存在することを検証します。
-
** API アップデート:**
- poll_id の UUID を受け入れて返すように API エンドポイントを変更します。
- すべての API 操作 (作成、更新、削除、投票) が一貫して UUID 形式を参照するようにします。
-
** テスト:**
- アプリケーションを徹底的にテストして、すべてのシナリオ (作成、更新、投票、投票結果の取得) で UUID が正しく処理されることを確認します。
-
** ドキュメント:**
- poll_id 形式の変更と、バージョン管理と UUID の使用に関連する新しい動作を反映するために API ドキュメントを更新します。
これらの手順に従うことで、データの整合性と履歴追跡を確保しながら、ポーリング システムに pollId の UUID を正常に実装できます。
ケース3
空または無効なオプション
検証アプローチ:
- API 入力検証: API エンドポイントにチェックを実装して、リクエスト本文で指定されたオプションが空ではなく、特定の基準を満たしていること (許可されていない場合は特殊文字がないことなど) を検証します。
- フィードバック メカニズム: オプションが無効または空の場合は、明確なエラー メッセージをユーザーに提供し、入力を修正するようにガイドします。
ケース4
オプションの重複
一意性チェック:
- 挿入前の検証: 投票にオプションを追加する前に、データベース内の既存のオプションに重複がないか確認してください。これは、ポーリング ID を使用してオプション テーブルをクエリし、新しいオプションと比較することで実行できます。
- ユーザー フィードバック: 重複したオプションが検出された場合は、意味のあるエラー メッセージを返してユーザーにどのオプションが重複しているかを知らせ、それに応じて入力を変更できるようにします。
事例5
質問の長さ制限
文字制限:
- API 検証: API 内のアンケートの質問とオプションの最大文字数制限を設定します。これは、作成および更新プロセス中に質問の長さと各オプションを確認することで実行できます。
- ユーザー インターフェイスのフィードバック: クライアント側の検証を実装して、ユーザーが入力中に文字数制限を超えた場合に即座にフィードバックを提供し、ユーザー エクスペリエンスを向上させます。
事例6
投票期限
有効期限のメカニズム:
- タイムスタンプ管理: 各投票がいつ作成されたかを記録するタイムスタンプ フィールドを投票テーブルに追加し、オプションで有効期限の別のフィールドを追加します。
- スケジュールされたチェック: 期限切れのポーリングを定期的にチェックし、データベース内で非アクティブとしてマークするバックグラウンド ジョブまたは cron タスクを実装します。これには、期限切れの投票への投票を阻止することも含まれる場合があります。
- ユーザー通知: オプションで、投票の作成者と参加者に有効期限が近づいていることを通知し、投票が非アクティブになる前に投票に参加できるようにします。
まず次の記事を参照してください:
低レベル設計: ポーリング システム: 基本
低レベル設計: ポーリング システム - Node.js と SQL の使用
詳細:
システム設計に関連するすべての記事を取得します
タグ: SystemDesignWithZeeshanAli
zeeshanali とのシステムデザイン
Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli
以上が低レベルの設計: ポーリング システム - エッジ ケースの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境
