<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ database - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ database - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 04:32:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/database/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use PostgreSQL as a Cache, Queue, and Search Engine ]]>
                </title>
                <description>
                    <![CDATA[ "Just use Postgres" has been circulating as advice for years, but most articles arguing for it are opinion pieces. I wanted hard numbers. So I built a benchmark suite that pits vanilla PostgreSQL agai ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-postgresql-as-a-cache-queue-and-search-engine/</link>
                <guid isPermaLink="false">69e7accfe43672781470ff97</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ backend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Databases ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Aaron Yong ]]>
                </dc:creator>
                <pubDate>Tue, 21 Apr 2026 16:58:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/6fcdd3c0-eead-42a7-b2f0-cf4c6a3d06dc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>"Just use Postgres" has been circulating as advice for years, but most articles arguing for it are opinion pieces. I wanted hard numbers.</p>
<p>So I built a benchmark suite that pits vanilla PostgreSQL against a feature-optimized PostgreSQL instance — measuring caching, message queues, full-text search, and pub/sub under controlled conditions.</p>
<p>In this article, you'll learn how to use PostgreSQL's built-in features for caching, job queues, full-text search, and pub/sub. You'll see actual benchmark results (latency percentiles, throughput, and error rates) comparing naive PostgreSQL patterns against optimized ones, and understand where PostgreSQL's limits are so you can decide whether you really need that extra service in your stack.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-the-setup">The Setup</a></p>
</li>
<li><p><a href="#heading-benchmark-1-caching-with-unlogged-tables">Benchmark 1: Caching with UNLOGGED Tables</a></p>
</li>
<li><p><a href="#heading-benchmark-2-job-queues-with-skip-locked">Benchmark 2: Job Queues with SKIP LOCKED</a></p>
</li>
<li><p><a href="#heading-benchmark-3-full-text-search-with-tsvector">Benchmark 3: Full-Text Search with tsvector</a></p>
</li>
<li><p><a href="#heading-benchmark-4-pubsub-with-listennotify">Benchmark 4: Pub/Sub with LISTEN/NOTIFY</a></p>
</li>
<li><p><a href="#heading-the-combined-workload-the-honest-test">The Combined Workload: The Honest Test</a></p>
</li>
<li><p><a href="#heading-what-i-learned">What I Learned</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along or reproduce the benchmarks, you'll need:</p>
<ul>
<li><p>Docker and Docker Compose</p>
</li>
<li><p>Node.js 20+ (for the Express TypeScript API layer)</p>
</li>
<li><p><a href="https://k6.io/">k6</a> for load testing</p>
</li>
<li><p>Basic familiarity with SQL and PostgreSQL</p>
</li>
</ul>
<p>The full benchmark project is <a href="https://github.com/aaronhsyong2/pg-stack-benchmark">open source on GitHub</a> — you can clone it and run every test yourself.</p>
<h2 id="heading-the-setup">The Setup</h2>
<p>The benchmark uses two identical PostgreSQL 17 instances running in Docker containers, each with fixed resource constraints (2 CPUs, 2 GB RAM). Both share the same Express TypeScript API layer — the only difference is which PostgreSQL features are enabled.</p>
<pre><code class="language-plaintext">┌─────────┐     ┌──────────────────┐     ┌─────────────────┐
│   k6    │────&gt;│  Express API     │────&gt;│  PG Baseline    │
│  (load  │     │  (TypeScript)    │     │  (vanilla PG17) │
│  test)  │────&gt;│  Port 3001/3002  │────&gt;│  PG Modded      │
└─────────┘     └──────────────────┘     │  (features on)  │
                                         └─────────────────┘
</code></pre>
<p>The baseline instance uses naïve approaches (regular tables, <code>ILIKE</code> search, polling). The modded instance uses PostgreSQL's built-in features (UNLOGGED tables, <code>tsvector</code> with GIN indexes, <code>LISTEN/NOTIFY</code>, partial indexes). Same hardware, same API code, same data. Only the database features differ.</p>
<p>Both instances share this tuned <code>postgresql.conf</code>:</p>
<pre><code class="language-ini"># Memory allocation
shared_buffers = 512MB           # 25% of available RAM
effective_cache_size = 1536MB    # 75% of RAM — helps the query planner
work_mem = 16MB                  # per-sort/hash operation memory

# SSD-optimized planner settings
random_page_cost = 1.1           # default 4.0 assumes spinning disks
effective_io_concurrency = 200   # allow parallel I/O on SSDs
</code></pre>
<p>These settings matter. The defaults assume spinning disks from the early 2000s. Setting <code>random_page_cost = 1.1</code> tells the query planner that random reads are nearly as fast as sequential reads on SSDs, which encourages index usage over sequential scans.</p>
<h2 id="heading-benchmark-1-caching-with-unlogged-tables">Benchmark 1: Caching with UNLOGGED Tables</h2>
<p><strong>The idea:</strong> Use an UNLOGGED table as an in-database cache. UNLOGGED tables skip PostgreSQL's Write-Ahead Log (WAL) — the mechanism that guarantees durability. Since cache data is ephemeral by nature, losing it on a crash is acceptable, and skipping WAL removes the biggest write bottleneck.</p>
<pre><code class="language-sql">-- Modded: UNLOGGED table for cache entries
CREATE UNLOGGED TABLE cache_entries (
    key TEXT PRIMARY KEY,
    value JSONB NOT NULL,
    expires_at TIMESTAMPTZ
);

-- Baseline: same schema, but a regular (logged) table
CREATE TABLE cache_entries (
    key TEXT PRIMARY KEY,
    value JSONB NOT NULL,
    expires_at TIMESTAMPTZ
);
</code></pre>
<h3 id="heading-results-200-virtual-users">Results (200 Virtual Users)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>avg</th>
<th>req/s</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline (regular table)</td>
<td>1.87ms</td>
<td>6.00ms</td>
<td>2.50ms</td>
<td>1,754/s</td>
</tr>
<tr>
<td>Modded (UNLOGGED table)</td>
<td>1.71ms</td>
<td>5.24ms</td>
<td>2.17ms</td>
<td>1,760/s</td>
</tr>
</tbody></table>
<p>A consistent 13% improvement across all percentiles. Not dramatic, but free — you change one keyword in your <code>CREATE TABLE</code> statement.</p>
<h3 id="heading-under-stress-1000-virtual-users-no-sleep">Under Stress (1,000 Virtual Users, No Sleep)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>req/s</th>
<th>Total Requests</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline</td>
<td>83.38ms</td>
<td>143.23ms</td>
<td>7,663/s</td>
<td>728,021</td>
</tr>
<tr>
<td>Modded</td>
<td>77.69ms</td>
<td>126.39ms</td>
<td>8,062/s</td>
<td>765,934</td>
</tr>
</tbody></table>
<p>The relative improvement stays locked at 12-13% regardless of load level. The UNLOGGED advantage is a per-write optimization — it saves the same amount of I/O whether you are doing 100 or 10,000 writes per second. The modded instance served 37,000 more requests in the same time window.</p>
<h3 id="heading-the-verdict">The Verdict</h3>
<p>UNLOGGED tables won't match Redis for sub-millisecond hot-path caching (real-time bidding, gaming leaderboards). But for web applications where the difference between 2ms and 5ms is invisible to users, they eliminate an entire infrastructure dependency for zero additional complexity.</p>
<p>You do give up Redis data structures (sorted sets, HyperLogLog, streams). If you need those, a dedicated cache is still the right call.</p>
<h2 id="heading-benchmark-2-job-queues-with-skip-locked">Benchmark 2: Job Queues with SKIP LOCKED</h2>
<p><strong>The idea:</strong> Use PostgreSQL as a job queue with <code>SELECT ... FOR UPDATE SKIP LOCKED</code>. Multiple workers poll the same table, and <code>SKIP LOCKED</code> ensures each worker gets a different row — no duplicates, no contention.</p>
<pre><code class="language-sql">-- Queue table with a partial index on pending jobs only
CREATE TABLE job_queue (
    id SERIAL PRIMARY KEY,
    payload JSONB NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending',
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Partial index: only indexes pending jobs
-- As jobs complete, they leave the index — it stays small forever
CREATE INDEX idx_pending_jobs ON job_queue (created_at)
    WHERE status = 'pending';
</code></pre>
<p>The dequeue pattern:</p>
<pre><code class="language-sql">-- Atomic dequeue: select + update in one statement
UPDATE job_queue SET status = 'processing'
WHERE id = (
    SELECT id FROM job_queue
    WHERE status = 'pending'
    ORDER BY created_at
    LIMIT 1
    FOR UPDATE SKIP LOCKED  -- skip rows locked by other workers
) RETURNING *;
</code></pre>
<p>How <code>SKIP LOCKED</code> works: Worker A locks row 1. Worker B tries row 1, sees the lock, skips it, and takes row 2 instead. No blocking, no duplicates. If a worker crashes, the transaction rolls back and the row becomes available again.</p>
<h3 id="heading-results-100-producers-50-consumers">Results (100 Producers + 50 Consumers)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>avg</th>
<th>req/s</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline (full index)</td>
<td>1.90ms</td>
<td>5.01ms</td>
<td>2.30ms</td>
<td>1,053/s</td>
</tr>
<tr>
<td>Modded (partial index)</td>
<td>1.81ms</td>
<td>5.28ms</td>
<td>2.29ms</td>
<td>1,052/s</td>
</tr>
</tbody></table>
<p>They're virtually identical. The partial index doesn't show its value in a 60-second benchmark because the table doesn't accumulate enough completed rows for the index size difference to matter. In a production system with millions of completed jobs, the partial index keeps the index at kilobytes while a full index grows to gigabytes.</p>
<h3 id="heading-the-verdict">The Verdict</h3>
<p><code>SKIP LOCKED</code> is production-ready for job queues. Libraries like <a href="https://github.com/timgit/pg-boss">pg-boss</a> (Node.js) and <a href="https://github.com/riverqueue/river">river</a> (Go) build on this exact pattern.</p>
<p>You do give up exchange/routing patterns (fan-out, topic-based routing) and consumer groups with message replay. If you need those, a dedicated message broker is still the right tool. For simple "process this job once" workloads, PostgreSQL handles it.</p>
<h2 id="heading-benchmark-3-full-text-search-with-tsvector">Benchmark 3: Full-Text Search with tsvector</h2>
<p><strong>The idea:</strong> Use PostgreSQL's built-in full-text search instead of a separate search service. A <code>tsvector</code> column stores pre-processed search tokens, and a GIN (Generalized Inverted Index) enables fast lookups using the same inverted index concept that powers Elasticsearch.</p>
<pre><code class="language-sql">-- Search-optimized article table
CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    body TEXT NOT NULL,
    search_vector tsvector  -- pre-computed search tokens
);

-- GIN index for full-text search
CREATE INDEX idx_search ON articles USING GIN (search_vector);

-- Auto-update search_vector on insert/update
CREATE OR REPLACE FUNCTION update_search_vector() RETURNS trigger AS $$
BEGIN
    NEW.search_vector := to_tsvector('english',
        COALESCE(NEW.title, '') || ' ' || COALESCE(NEW.body, ''));
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_search
    BEFORE INSERT OR UPDATE ON articles
    FOR EACH ROW EXECUTE FUNCTION update_search_vector();
</code></pre>
<p>The baseline uses <code>ILIKE</code> with a leading wildcard — the approach most developers reach for first:</p>
<pre><code class="language-sql">-- Baseline: sequential scan on every query
SELECT * FROM articles
WHERE title ILIKE '%postgresql%' OR body ILIKE '%postgresql%';

-- Modded: GIN index lookup with relevance ranking
SELECT id, title,
    ts_rank(search_vector, plainto_tsquery('english', 'postgresql')) AS rank
FROM articles
WHERE search_vector @@ plainto_tsquery('english', 'postgresql')
ORDER BY rank DESC LIMIT 20;
</code></pre>
<h3 id="heading-results-500-virtual-users">Results (500 Virtual Users)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>avg</th>
<th>req/s</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline (ILIKE)</td>
<td>1.96ms</td>
<td>101.83ms</td>
<td>25.22ms</td>
<td>561/s</td>
</tr>
<tr>
<td>Modded (tsvector + GIN)</td>
<td>2.76ms</td>
<td>10.39ms</td>
<td>3.76ms</td>
<td>675/s</td>
</tr>
</tbody></table>
<p>This is the standout result. The baseline's p95 of 101ms versus the modded's 10ms is a 10x improvement.</p>
<p>Why the baseline's p50 (1.96ms) is slightly better than the modded's (2.76ms): simple <code>ILIKE</code> queries on small result sets can be fast when the data fits in <code>shared_buffers</code>. But as load increases and the buffer cache is contested, sequential scans degrade dramatically. The GIN index stays stable.</p>
<h3 id="heading-under-stress-500-virtual-users-no-sleep">Under Stress (500 Virtual Users, No Sleep)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>req/s</th>
<th>Total Requests</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline (ILIKE)</td>
<td>599ms</td>
<td>1,000ms</td>
<td>558/s</td>
<td>50,212</td>
</tr>
<tr>
<td>Modded (tsvector)</td>
<td>209ms</td>
<td>396ms</td>
<td>1,441/s</td>
<td>129,679</td>
</tr>
</tbody></table>
<p>ILIKE collapses to 1-second p95 latencies. Each query forces a sequential scan of all 10,000 articles, blocking shared buffers and starving concurrent queries. The tsvector approach serves 2.6x more requests in the same time window because the GIN index lookup is O(log n) regardless of concurrency.</p>
<h3 id="heading-the-verdict">The Verdict</h3>
<p>This is the strongest argument in the entire benchmark. The fix requires zero extensions — <code>to_tsvector()</code>, <code>plainto_tsquery()</code>, and <code>CREATE INDEX USING GIN</code> are all built into core PostgreSQL. If you're doing <code>WHERE column ILIKE '%term%'</code> on any table with more than a few thousand rows, you're leaving massive performance on the table.</p>
<p>You do give up distributed search across shards, complex analyzers for CJK languages, and aggregation/faceted search pipelines. For a product search bar, blog search, or internal tool — PostgreSQL is enough.</p>
<h2 id="heading-benchmark-4-pubsub-with-listennotify">Benchmark 4: Pub/Sub with LISTEN/NOTIFY</h2>
<p><strong>The idea:</strong> Use PostgreSQL's native <code>LISTEN/NOTIFY</code> for pub/sub messaging, triggered automatically on INSERT via a database trigger.</p>
<pre><code class="language-sql">-- Trigger that fires pg_notify on every new message
CREATE OR REPLACE FUNCTION notify_message() RETURNS trigger AS $$
BEGIN
    PERFORM pg_notify(NEW.channel, NEW.payload::text);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_notify
    AFTER INSERT ON messages
    FOR EACH ROW EXECUTE FUNCTION notify_message();
</code></pre>
<h3 id="heading-results-200-virtual-users">Results (200 Virtual Users)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>avg</th>
<th>req/s</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline (poll-based)</td>
<td>1.99ms</td>
<td>6.04ms</td>
<td>2.84ms</td>
<td>1,116/s</td>
</tr>
<tr>
<td>Modded (LISTEN/NOTIFY)</td>
<td>1.65ms</td>
<td>4.80ms</td>
<td>2.13ms</td>
<td>1,131/s</td>
</tr>
</tbody></table>
<p>Here we have a 20% improvement at p95. The trigger-based approach does more work per INSERT (INSERT + NOTIFY), but the reduced round trips and better connection reuse patterns offset the overhead.</p>
<h3 id="heading-the-verdict">The Verdict</h3>
<p><code>LISTEN/NOTIFY</code> works for real-time features where you would otherwise reach for Redis pub/sub. The main limitation is payload size (8,000 bytes maximum) and the requirement for dedicated connections (incompatible with PgBouncer in transaction mode).</p>
<h2 id="heading-the-combined-workload-the-honest-test">The Combined Workload: The Honest Test</h2>
<p>Individual benchmarks are flattering. The real question: can one PostgreSQL instance handle caching, queues, search, and pub/sub simultaneously without degrading?</p>
<h3 id="heading-results-all-four-workloads-running-together">Results (All Four Workloads Running Together)</h3>
<table>
<thead>
<tr>
<th>Mode</th>
<th>p50</th>
<th>p95</th>
<th>avg</th>
<th>req/s</th>
</tr>
</thead>
<tbody><tr>
<td>Baseline</td>
<td>1.65ms</td>
<td>5.24ms</td>
<td>2.17ms</td>
<td>1,424/s</td>
</tr>
<tr>
<td>Modded</td>
<td>1.86ms</td>
<td>6.05ms</td>
<td>2.47ms</td>
<td>1,417/s</td>
</tr>
</tbody></table>
<p>Under combined load, the baseline marginally outperforms the modded setup. The modded PostgreSQL does more work per operation — maintaining GIN indexes, firing triggers, running <code>pg_cron</code> in the background. When all these features are active simultaneously, the overhead is measurable: about 15% higher p95 latency.</p>
<p>But both setups stay comfortably under 10ms at p95. For most web applications, that's more than good enough.</p>
<h2 id="heading-what-i-learned">What I Learned</h2>
<p>After running all these benchmarks, here's what I would tell a team evaluating whether to "just use Postgres":</p>
<ol>
<li><p><strong>Do it for full-text search:</strong> Switching from <code>ILIKE</code> to <code>tsvector</code> with a GIN index is a 10x improvement that requires zero extensions. This is the single highest-ROI change in the entire PostgreSQL ecosystem, and most developers don't know it exists.</p>
</li>
<li><p><strong>Do it for job queues:</strong> <code>SKIP LOCKED</code> is production-ready and eliminates RabbitMQ for simple "process this job" workloads. Use a library like pg-boss or river rather than rolling your own.</p>
</li>
<li><p><strong>Consider it for caching:</strong> UNLOGGED tables give a steady 13% improvement over regular tables. If sub-millisecond latency is not a hard requirement (and for most web apps, it is not), you can drop Redis entirely.</p>
</li>
<li><p><strong>Be honest about the overhead:</strong> Running all four roles simultaneously adds about 15% latency compared to running any single role. Whether that matters depends on your latency budget.</p>
</li>
<li><p><strong>Know where to stop:</strong> PostgreSQL won't match Redis for sub-millisecond caching, Kafka for millions of messages per second, or Elasticsearch for distributed multi-node search with complex analyzers. The line is at extreme throughput or extreme specialization.</p>
</li>
</ol>
<p>The honest conclusion is not "PostgreSQL does everything." It is: for most applications, a single well-configured PostgreSQL instance handles 80% of what you would otherwise need three to five additional services for. That is less infrastructure to deploy, monitor, and maintain — and fewer things to break at 3 AM.</p>
<p>Enterprise-scale applications processing millions of messages per second, serving sub-millisecond cache hits to millions of concurrent users, or running distributed search across terabytes of documents will still need specialized tools. Those tools exist for a reason, and at that scale the operational cost of running them is justified by the performance you get back.</p>
<p>But most of us aren't building at that scale — and may never need to. Starting with PostgreSQL for these roles means you ship faster with fewer moving parts. If and when you outgrow what PostgreSQL can handle, your benchmarks will tell you exactly which role needs to be extracted into a dedicated service. That is a much better position than starting with five services on day one because you assumed you would need them.</p>
<p>The <a href="https://github.com/aaronhsyong2/pg-stack-benchmark">benchmark project</a> is open source if you want to reproduce these results or adapt the tests for your own workload.</p>
<p>You can find more of my writing at <a href="https://site.aaronhsyong.com">site.aaronhsyong.com</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Store Data Locally with Isar in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ When building Flutter applications, managing local data efficiently is critical. You want a database that is lightweight, fast, and easy to integrate, especially if your app will work offline. Isar is one such database. It is a high-performance, easy... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/store-data-locally-with-isar-in-flutter/</link>
                <guid isPermaLink="false">68cd561cebc0d959d789d679</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ NoSQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Atuoha Anthony ]]>
                </dc:creator>
                <pubDate>Fri, 19 Sep 2025 13:09:48 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758287132737/7886bedc-374f-401d-b59c-04c59590e81f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building Flutter applications, managing local data efficiently is critical. You want a database that is lightweight, fast, and easy to integrate, especially if your app will work offline. Isar is one such database. It is a high-performance, easy-to-use NoSQL embedded database tailored for Flutter. With features like reactive queries, indexes, relationships, migrations, and transactions, Isar makes local data persistence both powerful and developer-friendly.</p>
<p>In this article, you’lll learn how to integrate Isar into a Flutter project, set up a data model, and perform the full range of CRUD (Create, Read, Update, Delete) operations. To make this practical, you’ll build a simple to-do app that allows users to create, view, update, and delete tasks.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-we-are-building">What We Are Building</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-isar-in-a-flutter-project">How to Set Up Isar in a Flutter Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-task-model">How to Create the Task Model</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-repository-for-crud-operations">How to Build the Repository for CRUD Operations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-crud-into-the-flutter-ui">How to Integrate CRUD into the Flutter UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-beyond-crud-advanced-features-of-isar">Beyond CRUD: Advanced Features of Isar</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before starting, ensure you have the following:</p>
<ol>
<li><p><strong>Flutter SDK</strong> installed (version 3.0 or above recommended).<br> Check your version with:</p>
<pre><code class="lang-bash"> flutter --version
</code></pre>
</li>
<li><p><strong>Dart knowledge</strong>: Familiarity with Dart syntax, classes, and async programming.</p>
</li>
<li><p><strong>Flutter basics</strong>: You should know how to set up a Flutter project, build widgets, and use <code>FutureBuilder</code> or <code>setState</code> for state management.</p>
</li>
<li><p><strong>Code editor</strong>: VS Code or Android Studio is recommended.</p>
</li>
</ol>
<p>If these are in place, we are ready to begin.</p>
<h2 id="heading-what-we-are-building">What We Are Building</h2>
<p>We will create a Task Manager App that lets users:</p>
<ul>
<li><p>Add new tasks.</p>
</li>
<li><p>View all tasks in a list.</p>
</li>
<li><p>Update existing tasks.</p>
</li>
<li><p>Delete tasks.</p>
</li>
</ul>
<p>By the end, you will have a fully functioning CRUD app built with Flutter and Isar.</p>
<h2 id="heading-how-to-set-up-isar-in-a-flutter-project">How to Set Up Isar in a Flutter Project</h2>
<h3 id="heading-step-1-add-dependencies">Step 1: Add dependencies</h3>
<p>Open your <code>pubspec.yaml</code> file and add the following:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">flutter:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
  <span class="hljs-attr">isar:</span> <span class="hljs-string">^3.1.0</span>
  <span class="hljs-attr">isar_flutter_libs:</span> <span class="hljs-string">^3.1.0</span>

<span class="hljs-attr">dev_dependencies:</span>
  <span class="hljs-attr">isar_generator:</span> <span class="hljs-string">^3.1.0</span>
  <span class="hljs-attr">build_runner:</span> <span class="hljs-string">any</span>
</code></pre>
<ul>
<li><p><code>isar</code>: The core Isar package.</p>
</li>
<li><p><code>isar_flutter_libs</code>: Required for Flutter integration.</p>
</li>
<li><p><code>isar_generator</code>: Used to generate code for your models.</p>
</li>
<li><p><code>build_runner</code>: Runs the code generator.</p>
</li>
</ul>
<p>Run:</p>
<pre><code class="lang-bash">flutter pub get
</code></pre>
<h3 id="heading-step-2-create-and-initialize-isar">Step 2: Create and initialize Isar</h3>
<p>Create a file named <code>isar_setup.dart</code>. This will handle the opening of the Isar database.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:isar/isar.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:path_provider/path_provider.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'task.dart'</span>; <span class="hljs-comment">// we will create this model soon</span>

<span class="hljs-keyword">late</span> <span class="hljs-keyword">final</span> Isar isar;

Future&lt;<span class="hljs-keyword">void</span>&gt; initializeIsar() <span class="hljs-keyword">async</span> {
  <span class="hljs-keyword">final</span> dir = <span class="hljs-keyword">await</span> getApplicationDocumentsDirectory();
  isar = <span class="hljs-keyword">await</span> Isar.open(
    [TaskSchema],
    directory: dir.path,
  );
}
</code></pre>
<p><strong>Explanation</strong>:</p>
<ul>
<li><p><code>getApplicationDocumentsDirectory()</code> provides a storage location for the database file.</p>
</li>
<li><p><code>Isar.open()</code> initializes the database and registers our <code>Task</code> schema.</p>
</li>
<li><p><code>late final Isar isar;</code> ensures we can access the database instance globally after initialization.</p>
</li>
</ul>
<h2 id="heading-how-to-create-the-task-model">How to Create the Task Model</h2>
<p>Now let’s define our data model for tasks. Create a file named <code>task.dart</code>.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:isar/isar.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'task.g.dart'</span>;

<span class="hljs-meta">@Collection</span>()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  Id id = Isar.autoIncrement; <span class="hljs-comment">// auto-incrementing primary key</span>

  <span class="hljs-keyword">late</span> <span class="hljs-built_in">String</span> name;

  <span class="hljs-keyword">late</span> <span class="hljs-built_in">DateTime</span> createdAt;

  Task(<span class="hljs-keyword">this</span>.name) : createdAt = <span class="hljs-built_in">DateTime</span>.now();
}
</code></pre>
<p><strong>Explanation</strong>:</p>
<ul>
<li><p><code>@Collection()</code> tells Isar this class represents a database collection.</p>
</li>
<li><p><code>Id id = Isar.autoIncrement;</code> creates a unique identifier automatically.</p>
</li>
<li><p><code>late String name;</code> stores the task name.</p>
</li>
<li><p><code>late DateTime createdAt;</code> stores the creation timestamp.</p>
</li>
<li><p><code>part 'task.g.dart';</code> links to the generated code, which will be created after running the code generator.</p>
</li>
</ul>
<p>Generate the code with:</p>
<pre><code class="lang-bash">flutter pub run build_runner build
</code></pre>
<p>This generates <code>task.g.dart</code>, which contains the necessary schema code.</p>
<h2 id="heading-how-to-build-the-repository-for-crud-operations">How to Build the Repository for CRUD Operations</h2>
<p>Create a new file called <code>task_repository.dart</code>. This will house the methods for interacting with the database.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:isar/isar.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'task.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'isar_setup.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskRepository</span> </span>{
  Future&lt;<span class="hljs-keyword">void</span>&gt; addTask(<span class="hljs-built_in">String</span> name) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">final</span> task = Task(name);
    <span class="hljs-keyword">await</span> isar.writeTxn(() <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">await</span> isar.tasks.put(task);
    });
  }

  Future&lt;<span class="hljs-built_in">List</span>&lt;Task&gt;&gt; getAllTasks() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> isar.tasks.where().findAll();
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; updateTask(Task task) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> isar.writeTxn(() <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">await</span> isar.tasks.put(task);
    });
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; deleteTask(Task task) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> isar.writeTxn(() <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">await</span> isar.tasks.delete(task.id);
    });
  }
}
</code></pre>
<p><strong>Explanation</strong>:</p>
<ul>
<li><p><code>addTask</code>: Creates a new task and saves it.</p>
</li>
<li><p><code>getAllTasks</code>: Reads all tasks from the database.</p>
</li>
<li><p><code>updateTask</code>: Updates an existing task by calling <code>.put()</code> again.</p>
</li>
<li><p><code>deleteTask</code>: Removes a task by its <code>id</code>.</p>
</li>
<li><p><code>isar.writeTxn</code>: Ensures operations run inside a transaction for safety and consistency.</p>
</li>
</ul>
<h2 id="heading-how-to-integrate-crud-into-the-flutter-ui">How to Integrate CRUD into the Flutter UI</h2>
<p>Now, let’s connect everything inside <code>main.dart</code>.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'isar_setup.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'task_repository.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'task.dart'</span>;

<span class="hljs-keyword">void</span> main() <span class="hljs-keyword">async</span> {
  WidgetsFlutterBinding.ensureInitialized();
  <span class="hljs-keyword">await</span> initializeIsar(); <span class="hljs-comment">// initialize Isar before runApp</span>
  runApp(MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: TaskListScreen(),
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskListScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _TaskListScreenState createState() =&gt; _TaskListScreenState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_TaskListScreenState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">TaskListScreen</span>&gt; </span>{
  <span class="hljs-keyword">final</span> TaskRepository _taskRepository = TaskRepository();
  <span class="hljs-keyword">late</span> Future&lt;<span class="hljs-built_in">List</span>&lt;Task&gt;&gt; _tasksFuture;

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-keyword">super</span>.initState();
    _tasksFuture = _taskRepository.getAllTasks();
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; _addTask() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> _taskRepository.addTask(<span class="hljs-string">'New Task'</span>);
    setState(() {
      _tasksFuture = _taskRepository.getAllTasks();
    });
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; _deleteTask(Task task) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> _taskRepository.deleteTask(task);
    setState(() {
      _tasksFuture = _taskRepository.getAllTasks();
    });
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: Text(<span class="hljs-string">'Isar CRUD Example'</span>)),
      body: FutureBuilder&lt;<span class="hljs-built_in">List</span>&lt;Task&gt;&gt;(
        future: _tasksFuture,
        builder: (context, snapshot) {
          <span class="hljs-keyword">if</span> (snapshot.connectionState == ConnectionState.waiting) {
            <span class="hljs-keyword">return</span> Center(child: CircularProgressIndicator());
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (snapshot.hasError) {
            <span class="hljs-keyword">return</span> Center(child: Text(<span class="hljs-string">'Error: <span class="hljs-subst">${snapshot.error}</span>'</span>));
          } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">final</span> tasks = snapshot.data ?? [];
            <span class="hljs-keyword">if</span> (tasks.isEmpty) {
              <span class="hljs-keyword">return</span> Center(child: Text(<span class="hljs-string">'No tasks yet.'</span>));
            }
            <span class="hljs-keyword">return</span> ListView.builder(
              itemCount: tasks.length,
              itemBuilder: (context, index) {
                <span class="hljs-keyword">final</span> task = tasks[index];
                <span class="hljs-keyword">return</span> ListTile(
                  title: Text(task.name),
                  subtitle: Text(<span class="hljs-string">'Created at: <span class="hljs-subst">${task.createdAt}</span>'</span>),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () =&gt; _deleteTask(task),
                  ),
                );
              },
            );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _addTask,
        child: Icon(Icons.add),
      ),
    );
  }
}
</code></pre>
<p><strong>Explanation</strong>:</p>
<ul>
<li><p><code>initializeIsar()</code>: Ensures the database is ready before the app runs.</p>
</li>
<li><p><code>_tasksFuture</code>: Holds a future of the list of tasks.</p>
</li>
<li><p><code>_addTask</code>: Adds a new task and refreshes the list.</p>
</li>
<li><p><code>_deleteTask</code>: Deletes a task and refreshes the list.</p>
</li>
<li><p><code>FutureBuilder</code>: Automatically rebuilds the UI when the future completes.</p>
</li>
<li><p><code>ListView.builder</code>: Displays all tasks dynamically.</p>
</li>
</ul>
<p>This gives you a simple yet complete CRUD app using Isar.</p>
<h2 id="heading-beyond-crud-advanced-features-of-isar">Beyond CRUD: Advanced Features of Isar</h2>
<p>Once you are comfortable with CRUD, Isar provides advanced tools to optimize and extend your application:</p>
<ol>
<li><p><strong>Reactive Queries</strong>:<br> Instead of using <code>FutureBuilder</code>, you can listen for changes directly.</p>
<pre><code class="lang-dart"> <span class="hljs-keyword">final</span> stream = isar.tasks.where().watch(fireImmediately: <span class="hljs-keyword">true</span>);
</code></pre>
</li>
<li><p><strong>Indexes</strong>:<br> Improve query performance by indexing fields.</p>
<pre><code class="lang-dart"> <span class="hljs-meta">@Collection</span>()
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
   Id id = Isar.autoIncrement;

   <span class="hljs-meta">@Index</span>()
   <span class="hljs-keyword">late</span> <span class="hljs-built_in">String</span> name;
 }
</code></pre>
</li>
<li><p><strong>Relations</strong>:<br> Link one collection to another (for example, <code>Project</code> with many <code>Tasks</code>).</p>
</li>
<li><p><strong>Custom Queries</strong>:<br> Perform complex filtering, sorting, and pagination.</p>
</li>
<li><p><strong>Migrations</strong>:<br> Safely evolve your schema as the app grows.</p>
</li>
<li><p><strong>Batch Operations</strong>:<br> Insert or update many records in one transaction.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We built a simple Flutter to-do app with Isar that supports creating, reading, updating, and deleting tasks. Along the way, we learned how to:</p>
<ol>
<li><p>Add Isar dependencies.</p>
</li>
<li><p>Define a model with annotations.</p>
</li>
<li><p>Generate schema code.</p>
</li>
<li><p>Implement CRUD operations in a repository.</p>
</li>
<li><p>Connect Isar to the Flutter UI.</p>
</li>
</ol>
<p>With its performance, developer-friendly API, and advanced features, Isar is an excellent choice for local persistence in Flutter applications.</p>
<p>For further learning, consult the official docs:</p>
<ol>
<li><p><a target="_blank" href="https://pub.dev/packages/isar">Isar on pub.dev</a></p>
</li>
<li><p><a target="_blank" href="https://isar.dev/">Isar documentation</a></p>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle MongoDB Migrations with ts-migrate-mongoose ]]>
                </title>
                <description>
                    <![CDATA[ Database migrations are modifications made to a database. These modifications may include changing the schema of a table, updating the data in a set of records, seeding data or deleting a range of records. Database migrations are usually run before a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/handle-mongodb-migrations-with-ts-migrate-mongoose/</link>
                <guid isPermaLink="false">6747274cb7666002fd1cb1a6</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Orim Dominic Adah ]]>
                </dc:creator>
                <pubDate>Wed, 27 Nov 2024 14:06:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732615343335/0a1b3e5e-bfa7-4f57-81a7-7f4bac9e8b0a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Database migrations are modifications made to a database. These modifications may include changing the schema of a table, updating the data in a set of records, seeding data or deleting a range of records.</p>
<p>Database migrations are usually run before an application starts and do not run successfully more than once for the same database. Database migration tools save a history of migrations that have run in a database so that they can be tracked for future purposes.</p>
<p>In this article, you’ll learn how to set up and run database migrations in a minimal Node.js API application. We will use <a target="_blank" href="https://www.npmjs.com/package/ts-migrate-mongoose">ts-migrate-mongoose</a> and an npm script to create a migration and seed data into a MongoDB database. ts-migrate-mongoose supports running migration scripts from TypeScript code as well as CommonJS code.</p>
<p>ts-migrate-mongoose is a migration framework for Node.js projects that use <a target="_blank" href="https://www.npmjs.com/package/mongoose">mongoose</a> as the object-data mapper. It provides a template for writing migration scripts. It also provides a configuration to run the scripts programmatically and from the CLI.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-ts-migrate-mongoose-for-the-project">How to Configure ts-migrate-mongoose for the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-seed-user-data-with-ts-migrate-mongoose">How to Seed User Data with ts-migrate-mongoose</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-an-api-endpoint-to-fetch-seeded-data">How to Build an API Endpoint to Fetch Seeded Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>To use ts-migrate-mongoose for database migrations, you need to have the following:</p>
<ol>
<li><p>A Node.js project with mongoose installed as a dependency.</p>
</li>
<li><p>A MongoDB database connected to the project.</p>
</li>
<li><p>MongoDB Compass (Optional – to enable us view the changes in the database).</p>
</li>
</ol>
<p>A starter repository which can be cloned from <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo">ts-migrate-mongoose-starter-repo</a> has been created for ease. Clone the repository, fill the environment variables and start the application by running the <code>npm start</code> command.</p>
<p>Visit <a target="_blank" href="http://localhost:8000">http://localhost:8000</a> with a browser or an API client such as Postman and the server will return a "Hello there!" text to show that the starter application runs as expected.</p>
<h2 id="heading-how-to-configure-ts-migrate-mongoose-for-the-project">How to Configure ts-migrate-mongoose for the Project</h2>
<p>To configure ts-migrate-mongoose for the project, install ts-migrate-mongoose with this command:</p>
<pre><code class="lang-bash">npm install ts-migrate-mongoose
</code></pre>
<p>ts-migrate-mongoose allows configuration with a JSON file, a TypeScript file, a <code>.env</code> file or via the CLI. It is advisable to use a <code>.env</code> file because the content of the configuration may contain a database password and it is not proper to have that exposed to the public. <code>.env</code> files are usually hidden via <code>.gitignore</code> files so they are more secure to use. This project will use a <code>.env</code> file for the ts-migrate-mongoose configuration.</p>
<p>The file should contain the following keys and their values:</p>
<ul>
<li><p><code>MIGRATE_MONGO_URI</code> - the URI of the Mongo database. It is the same as the database URL.</p>
</li>
<li><p><code>MIGRATE_MONGO_COLLECTION</code> - the name of the collection (or table) which migrations should be saved in. The default value is migrations which is what is used in this project. ts-migrate-mongoose saves migrations to MongoDB.</p>
</li>
<li><p><code>MIGRATE_MIGRATIONS_PATH</code> - the path to the folder for storing and reading migration scripts. The default value is <code>./migrations</code> which is what is used in this project.</p>
</li>
</ul>
<h2 id="heading-how-to-seed-user-data-with-ts-migrate-mongoose">How to Seed User Data with ts-migrate-mongoose</h2>
<p>We have been able to create a project and connect it successfully to a Mongo database. At this point, we want to seed user data into the database. We need to:</p>
<ol>
<li><p>Create a users collection (or table)</p>
</li>
<li><p>Use ts-migrate-mongoose to create a migration script to seed data</p>
</li>
<li><p>Use ts-migrate-mongoose to run the migration to seed the user data into the database before the application starts</p>
</li>
</ol>
<h3 id="heading-1-create-a-users-collection-using-mongoose">1. Create a users Collection using Mongoose</h3>
<p>Mongoose schema can be used to create a user collection (or table). User documents (or records) will have the following fields (or columns): <code>email</code>, <code>favouriteEmoji</code> and <code>yearOfBirth</code>.</p>
<p>To create a Mongoose schema for the user collection, create a <code>user.model.js</code> file in the root of the project containing the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
  {
    <span class="hljs-attr">email</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">lowercase</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">favouriteEmoji</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">yearOfBirth</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
  {
    <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>,
  }
);

<span class="hljs-built_in">module</span>.exports.UserModel = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
</code></pre>
<h3 id="heading-2-create-a-migration-script-with-ts-migrate-mongoose">2. Create a Migration Script with ts-migrate-mongoose</h3>
<p>ts-migrate-mongoose provides CLI commands which can be used to create migration scripts.</p>
<p>Running <code>npx migrate create &lt;name-of-script&gt;</code> in the root folder of the project will create a script in the <code>MIGRATE_MIGRATIONS_PATH</code> folder (<code>./migrations</code> in our case). <code>&lt;name-of-script&gt;</code> is the name we want the migration script file to have when it is created.</p>
<p>To create a migration script to seed user data, run:</p>
<pre><code class="lang-bash">npx migrate create seed-users
</code></pre>
<p>The command will create a file in the <code>./migrations</code> folder with a name in the form -<code>&lt;timestamp&gt;-seed-users.ts</code>. The file will have the following code snippet content:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Import your models here</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-comment">// Write migration here</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">down</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-comment">// Write migration here</span>
}
</code></pre>
<p>The <code>up</code> function is used to run the migration. The <code>down</code> function is used to reverse whatever the <code>up</code> function executes, if need be. In our case, we are trying to seed users into the database. The <code>up</code> function will contain code to seed users into the database and the <code>down</code> function will contain code to delete users created in the <code>up</code> function.</p>
<p>If the database is inspected with MongoDB Compass, the migrations collection will have a document that looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"_id"</span>: ObjectId(<span class="hljs-string">"6744740465519c3bd9c1a7d1"</span>),
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"seed-users"</span>,
  <span class="hljs-attr">"state"</span>: <span class="hljs-string">"down"</span>,
  <span class="hljs-attr">"createdAt"</span>: <span class="hljs-number">2024</span><span class="hljs-number">-11</span><span class="hljs-number">-25</span>T12:<span class="hljs-number">56</span>:<span class="hljs-number">36.316</span>+<span class="hljs-number">00</span>:<span class="hljs-number">00</span>,
  <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-number">2024</span><span class="hljs-number">-11</span><span class="hljs-number">-25</span>T12:<span class="hljs-number">56</span>:<span class="hljs-number">36.316</span>+<span class="hljs-number">00</span>:<span class="hljs-number">00</span>,
  <span class="hljs-attr">"__v"</span>: <span class="hljs-number">0</span>
}
</code></pre>
<p>The <code>state</code> field of the migration document is set to <code>down</code>. After it runs successfully, it changes to <code>up</code>.</p>
<p>You can update the code in <code>./migrations/&lt;timestamp&gt;-seed-users.ts</code> to the one in the snippet below:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config() <span class="hljs-comment">// load env variables</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../db.js"</span>)
<span class="hljs-keyword">const</span> { UserModel } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../user.model.js"</span>);

<span class="hljs-keyword">const</span> seedUsers = [
  { email: <span class="hljs-string">"john@email.com"</span>, favouriteEmoji: <span class="hljs-string">"🏃"</span>, yearOfBirth: <span class="hljs-number">1997</span> },
  { email: <span class="hljs-string">"jane@email.com"</span>, favouriteEmoji: <span class="hljs-string">"🍏"</span>, yearOfBirth: <span class="hljs-number">1998</span> },
];

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-keyword">await</span> db.connect(process.env.MONGO_URI)
  <span class="hljs-keyword">await</span> UserModel.create(seedUsers);}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">down</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-keyword">await</span> db.connect(process.env.MONGO_URI)
  <span class="hljs-keyword">await</span> UserModel.delete({
    email: {
      $in: seedUsers.map(<span class="hljs-function">(<span class="hljs-params">u</span>) =&gt;</span> u.email),
    },
  });
}
</code></pre>
<h3 id="heading-3-run-the-migration-before-the-application-starts">3. Run the Migration Before the Application Starts</h3>
<p>ts-migrate-mongoose provides us with CLI commands to run the <code>up</code> and <code>down</code> function of migration scripts.</p>
<p>With <code>npx migrate up &lt;name-of-script&gt;</code> we can run the <code>up</code> function of a specific script. With <code>npx migrate up</code> we can run the <code>up</code> function of all scripts in the <code>./migrations</code> folder with a <code>state</code> of <code>down</code> in the database.</p>
<p>To run the migration before the application starts, we make use of npm scripts. npm scripts with a prefix of <code>pre</code> will run before a script without the <code>pre</code> prefix. For example, if there is a <code>dev</code> script and a <code>predev</code> script, whenever the <code>dev</code> script is run with <code>npm run dev</code>, the <code>predev</code> script will automatically run before the <code>dev</code> script is run.</p>
<p>We will use this feature of npm scripts to place the ts-migrate-mongoose command in a <code>prestart</code> script so that the migration will run before the <code>start</code> script.</p>
<p>Update the <code>package.json</code> file to have a <code>prestart</code> script that runs the ts-migrate-mongoose command for running the <code>up</code> function of migration scripts in the project.</p>
<pre><code class="lang-json">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"prestart"</span>: <span class="hljs-string">"npx migrate up"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node index.js"</span>
  },
</code></pre>
<p>With this setup, when <code>npm run start</code> is executed to start the application, the <code>prestart</code> script will run to execute the migration using ts-migrate-mongoose and seed the database before the application starts.</p>
<p>You should have something similar to the snippet below after running <code>npm run start</code>:</p>
<pre><code class="lang-bash">Synchronizing database with file system migrations...
MongoDB connection successful
up: 1732543529744-seed-users.ts 
All migrations finished successfully

&gt; ts-migrate-mongoose-starter-repo@1.0.0 start
&gt; node index.js

MongoDB connection successful                      
Server listening on port 8000
</code></pre>
<p>Check out the <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo/tree/seed-users">seed-users</a> branch of the repository to see the current status of the codebase at this point in the article.</p>
<h2 id="heading-how-to-build-an-api-endpoint-to-fetch-seeded-data">How to Build an API Endpoint to Fetch Seeded Data</h2>
<p>We can build an API endpoint to fetch the seeded users data in our database. In the <code>server.js</code> file, update the code to the one in the snippet below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { UserModel } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./user.model.js"</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> UserModel.find({}) <span class="hljs-comment">// fetch all the users in the database</span>

  res.writeHead(<span class="hljs-number">200</span>, { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> });
  <span class="hljs-keyword">return</span> res.end(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-comment">// return a JSON representation of the fetched users data</span>
    <span class="hljs-attr">users</span>: users.map(<span class="hljs-function">(<span class="hljs-params">u</span>) =&gt;</span> ({
      <span class="hljs-attr">email</span>: u.email,
      <span class="hljs-attr">favouriteEmoji</span>: u.favouriteEmoji,
      <span class="hljs-attr">yearOfBirth</span>: u.yearOfBirth,
      <span class="hljs-attr">createdAt</span>: u.createdAt
    }))
  }, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
};
</code></pre>
<p>If we start the application and visit <a target="_blank" href="http://localhost:8000">http://localhost:8000</a> using Postman or a browser, we get a JSON response similar to the one below:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"users"</span>: [
    {
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"john@email.com"</span>,
      <span class="hljs-attr">"favouriteEmoji"</span>: <span class="hljs-string">"🏃"</span>,
      <span class="hljs-attr">"yearOfBirth"</span>: <span class="hljs-number">1997</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-11-25T14:18:55.416Z"</span>
    },
    {
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jane@email.com"</span>,
      <span class="hljs-attr">"favouriteEmoji"</span>: <span class="hljs-string">"🍏"</span>,
      <span class="hljs-attr">"yearOfBirth"</span>: <span class="hljs-number">1998</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-11-25T14:18:55.416Z"</span>
    }
  ]
}
</code></pre>
<p>Notice that if the application is run again, the migration script does not run anymore because the <code>state</code> of the migration will now be <code>up</code> after it has run successfully.</p>
<p>Check out the <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo/tree/fetch-users">fetch-users</a> branch of the repository to see the current status of the codebase at this point in the article.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Migrations are useful when building applications and there is need to seed initial data for testing, seeding administrative users, updating database schema by adding or removing columns and updating the values of columns in many records at once.</p>
<p>ts-migrate-mongoose can help provide a framework for running migrations for your Node.js applications if you use Mongoose with MongoDB.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Object Relational Mapping in Node.js – Optimize Database Interactions With Sequelize ORM ]]>
                </title>
                <description>
                    <![CDATA[ Databases play a vital role in the development of applications across mobile and web platforms. Adequate knowledge of data interactions between the application structure and the database is essential for storing relevant application data. Object-rela... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/object-relational-mapping-in-nodejs-with-sequelize-orm/</link>
                <guid isPermaLink="false">670fa2e2c038b5fdec128d46</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Wed, 16 Oct 2024 11:26:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728644693143/667b7624-6dc2-407a-828b-f5b6c1844ac8.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Databases play a vital role in the development of applications across mobile and web platforms. Adequate knowledge of data interactions between the application structure and the database is essential for storing relevant application data.</p>
<p>Object-relational mapping, as a programming concept, is an efficient standard protocol for facilitating seamless connection with databases. But what does it really mean, and how do you set it up as a developer? We’ll answer these questions and highlight more about object-relational mapping.</p>
<p>Here are the prerequisites:</p>
<ul>
<li><p>Knowledge of Node.js</p>
</li>
<li><p>Use the Express framework</p>
</li>
<li><p>An installed MySQL database</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-table-of-contents">Table of Contents</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-an-orm">What is an ORM?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-nodejs-server">How to Set Up Your Node.js Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-relevant-packages">How to Integrate Relevant Packages</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-demo-project">Demo Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-additional-information">Additional Information</a></p>
</li>
</ul>
<h2 id="heading-what-is-an-orm">What is an ORM?</h2>
<p>Object Relational Mapping (ORM) is a database communication concept in programming that involves the abstraction of data types as compatible object-oriented programming variables. It simply eliminates the use of database-defined queries and storage types to allow ease of creating databases via the programming languages.</p>
<p>Its use has been widely adopted in the tech space as has more advantages than conventional database query methods. Here are some of them:</p>
<ul>
<li><p>It reduces the risk of data manipulation: SQL and non-SQL injections involve inputting malicious SQL syntaxes and queries into the database, which can compromise database security. Having an ORM in place adds an input validation scheme feature, and details the expected input variable syntax and processes it accordingly.</p>
</li>
<li><p>Ease of database communication: ORM serves to simplify the use of databases as a data tool without undergoing the process of learning a different database query language. The ORM schema can be highlighted in an object-oriented fashion in the application language and can be configured to automatically translate the code to queries compatible with the database.</p>
</li>
<li><p>This feature also allows easy code portability, achieving maintenance of a single database integration code base while changing the database without any adverse outcome. It is highly flexible and can be used in any database of choice.</p>
</li>
<li><p>It also has additional features included to allow database interactions. Database migration features and version control processes are provided. With these, we have seen some of its benefits, we will then highlight popular ORM tools used globally.</p>
</li>
</ul>
<p>Here are the popular ORM tools:</p>
<ul>
<li><p><a target="_blank" href="https://docs.sqlalchemy.org/">SQLAlchemy</a></p>
</li>
<li><p><a target="_blank" href="https://www.prisma.io/">Prisma ORM</a></p>
</li>
<li><p><a target="_blank" href="https://sequelize.org/">Sequelize</a></p>
</li>
<li><p><a target="_blank" href="https://guides.rubyonrails.org/active_record_basics.html">ActiveRecord</a></p>
</li>
<li><p><a target="_blank" href="https://typeorm.io/">TypeORM</a></p>
</li>
<li><p><a target="_blank" href="https://sailsjs.com/documentation/reference/waterline-orm">Waterline</a></p>
</li>
</ul>
<p>For this article, we’ll be streamlining our ORM use cases to a basic Node.js project linked to a MySQL database. We’ll use the Sequelize ORM as the tool of choice.</p>
<p>With an average package download of 8.5 million monthly and an active development community, Sequelize boasts robust features that seamlessly integrate databases with backend applications. It also provides a user oriented documentation which helps guide the user on setting up and using the tool.</p>
<p>Here is a link to <a target="_blank" href="https://sequelize.org/docs/v6/getting-started/">the documentation</a>. It also offers support for MySQL, DB2, and SQLite Microsoft SQL server, and it offers features such as read replication, lazy loading, and efficient database transaction properties.</p>
<p>Next, we’ll set up our web application and install Sequelize to connect us to a MySQL database hosted locally.</p>
<h2 id="heading-how-to-set-up-your-nodejs-server">How to Set Up Your Node.js Server</h2>
<p>In this section you’ll set up our Node server. Navigate to the command line and execute <code>npm init</code>. This command creates a new Node project structure for you.</p>
<p>Next, install the Express package – this will serve as the backend framework. You can do this by running the <code>npm i express</code> command.</p>
<h2 id="heading-how-to-integrate-relevant-packages">How to Integrate Relevant Packages</h2>
<p>For the purpose of this tutorial, we’ll install the Sequelize Node package manager in our Node application in order to set up the ORM communication to the database.</p>
<p>To set this up, execute <code>npm i sequelize</code>.</p>
<p>We’ll use a locally hosted MySQL database. To do this, we’ll install an npm package database driver. In this case, we will be installing <code>mysql2</code>. Here is a link to the <a target="_blank" href="https://www.npmjs.com/package/sequelize"><code>package</code></a></p>
<p>Run <code>npm i mysql2</code> to install it.</p>
<p>Let’s move on to configuring the connection to the database and building our demo project.</p>
<h2 id="heading-demo-project">Demo Project</h2>
<p>In this section we’ll build a simple backend server that performs Create-Read-Update-Delete operations, with the Sequelize library serving as the connection pipeline.</p>
<p>In order to begin the project, we’ll have to set up the database connection for our application. We’ll create a database connection file and set up our database credentials. You can name the file <strong>SequelizeConfig</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {

    <span class="hljs-attr">HOST</span>: <span class="hljs-string">"localhost"</span>,

    <span class="hljs-attr">USER</span>: <span class="hljs-string">"root"</span>,

    <span class="hljs-attr">PASSWORD</span>: <span class="hljs-string">""</span>,

    <span class="hljs-attr">DB</span>: <span class="hljs-string">"sequel"</span>,

    <span class="hljs-attr">dialect</span>: <span class="hljs-string">"mysql"</span>

}
</code></pre>
<p>In the code above, the database credentials were specified, along with the host address. In our case, the database is locally hosted, so localhost is the default host.</p>
<p>The database login details were also provided. The user here is the root, while the password was set to an empty string. This should be tweaked to ensure database security. I also created a defunct database named “sequel”.</p>
<p>The dialect refers to the type of database the user intends to use. In our case, the dialect is MySQL. Note that this can also be replicated on a cloud hosted database with the credentials obtained. With that, let's integrate the connection file with the application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> SequelConfig = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../config/sequelize'</span>);

<span class="hljs-keyword">const</span> Sequelize = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sequelize'</span>);

<span class="hljs-keyword">const</span> sequelize = <span class="hljs-keyword">new</span> Sequelize(SequelCOnfig.DB, SequelCOnfig.USER, SequelCOnfig.PASSWORD, {

    <span class="hljs-attr">host</span>: SequelCOnfig.HOST,

    <span class="hljs-attr">dialect</span>: SequelCOnfig.dialect

});
</code></pre>
<p>In order to facilitate a connection to the database, the variables in the config file were imported and initialized in the Sequelize setup file.</p>
<pre><code class="lang-javascript">

<span class="hljs-keyword">const</span> db = {};

db.Sequelize = Sequelize;

db.sequelize = sequelize;

db.user = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../model/user.model'</span>)(sequelize, Sequelize);

db.token = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../model/token.model'</span>)(sequelize, Sequelize)

<span class="hljs-built_in">module</span>.exports= db;
</code></pre>
<p>This file above imports the <code>config</code> file created previously and initializes the Sequelize library. The code then fetches the database details inputted in the config file and, when executed, creates the database.</p>
<p>Furthermore, the various database models which will be discussed subsequently are then integrated with the defunct database and generates a SQL database table .</p>
<p>To get this up and running, the database file created is invoked using the <code>sequelize.sync()</code> method. Any error encountered is logged and the database connection gets terminated.</p>
<pre><code class="lang-javascript">db.sequelize.sync().then(<span class="hljs-function">() =&gt;</span> {

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'user created '</span>);

}).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {

  <span class="hljs-built_in">console</span>.error(err)

})
</code></pre>
<p>We’ll go on to discuss the database models.</p>
<h3 id="heading-models">Models</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Sequelize = <span class="hljs-built_in">require</span>(<span class="hljs-string">"sequelize"</span>);

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">sequelize</span>) =&gt;</span> {

sequelize.define(

<span class="hljs-string">"user"</span>, {

<span class="hljs-attr">firstName</span>: {

<span class="hljs-attr">type</span> : Sequelize.DataTypes.STRING,

<span class="hljs-attr">allowNull</span> : <span class="hljs-literal">false</span>

},

<span class="hljs-attr">lastName</span>: {

<span class="hljs-attr">type</span> : Sequelize.DataTypes.STRING,

<span class="hljs-attr">allowNull</span> : <span class="hljs-literal">false</span>

},

<span class="hljs-attr">email</span> : {

<span class="hljs-attr">type</span> : Sequelize.DataTypes.STRING,

<span class="hljs-attr">allowNull</span> : <span class="hljs-literal">false</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>

},

<span class="hljs-attr">password</span>: {

<span class="hljs-attr">type</span> : Sequelize.DataTypes.STRING,

<span class="hljs-attr">allowNull</span> : <span class="hljs-literal">false</span>

},

<span class="hljs-attr">role</span>:  {

<span class="hljs-attr">type</span> : Sequelize.DataTypes.STRING,

<span class="hljs-attr">allowNull</span> : <span class="hljs-literal">false</span>

}

}

)

}
</code></pre>
<p>In the code above, the user model was initialized in Sequelize ORM and the field details were specified: <code>email</code>, <code>role</code>, <code>lastName</code>, and <code>password</code>. The type of data to be received was also specified.</p>
<p>It also provides an option to ensure the uniqueness of the user details, and the option to prevent the user from leaving some fields empty via the use of <code>allowNull = false</code>.</p>
<p>On execution of the application, the Sequelize ORM creates an SQL equivalent of the model as a data table.</p>
<p>Next, we’ll work on the CRUD functions in Node.js.</p>
<h3 id="heading-create-operation">Create Operation</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> createUser = <span class="hljs-keyword">async</span> (userInfo) =&gt; {

<span class="hljs-keyword">try</span> {

<span class="hljs-comment">// Check if the email already exists in the database</span>

<span class="hljs-keyword">const</span> ifEmailExists = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">email</span>: userInfo.email } });

<span class="hljs-keyword">if</span> (ifEmailExists) {

<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(<span class="hljs-string">'Email has already been registered'</span>);

}

<span class="hljs-comment">// Create the new user</span>

<span class="hljs-keyword">const</span> newUser = <span class="hljs-keyword">await</span> User.create(userInfo);

<span class="hljs-keyword">return</span> newUser; <span class="hljs-comment">// Return the created user object</span>

} <span class="hljs-keyword">catch</span> (error) {

<span class="hljs-comment">// Handle errors such as validation or uniqueness constraint</span>

<span class="hljs-keyword">throw</span> error;

}

};
</code></pre>
<p>The function above highlights the controller function for creating user entries in the Express server.</p>
<p>The function is asynchronous, which allows for execution of some commands before eventual execution. The code ensures that the user email doesn’t exist in the database before cresting a new user.</p>
<p>In addition, we also ensured that each email field is unique. If the user details are entered into the database successfully, a “successful” response is sent back to the server. Additionally, any error encountered leads to termination of the function and the error gets sent back to the server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728593905405/ae2b4fb6-0dfd-4e68-890b-a5d1afc88d71.png" alt="A POST request to create a new user endpoint" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-read-operation">Read Operation</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> FetchUser = <span class="hljs-keyword">async</span> (userId) =&gt; {

<span class="hljs-keyword">let</span> userDets;

<span class="hljs-keyword">if</span> (userId) {

<span class="hljs-comment">// Fetch a single user by ID if userId is provided</span>

userDets = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: userId } });

<span class="hljs-comment">// Check if the user exists</span>

<span class="hljs-keyword">if</span> (!userDets) {

<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(httpStatus.NOT_FOUND, <span class="hljs-string">'User not found'</span>);

}

} <span class="hljs-keyword">else</span> {

<span class="hljs-comment">// Fetch all users if no userId is provided</span>

userDets = <span class="hljs-keyword">await</span> User.findAll();

<span class="hljs-comment">// Check if any users were found</span>

<span class="hljs-keyword">if</span> (userDets.length === <span class="hljs-number">0</span>) {

<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(httpStatus.NOT_FOUND, <span class="hljs-string">'No users found'</span>);

}

}
</code></pre>
<p>The read operation fetches the desired query and sends it back to the user without modification. The user ID, which should be unique, is used to search for a specific user. In this scenario, we want access to all the users created in the database.</p>
<p>In case the requested query is not found, an appropriate error code is generated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728593791809/3e4dae9d-98ad-4966-b17a-b9649c41921d.png" alt="A GET request  to fetch all the users in the database endpoint" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-update-operation">Update Operation</h3>
<pre><code class="lang-javascript">

<span class="hljs-keyword">const</span> updateUser = <span class="hljs-keyword">async</span> (userId, userDetails) =&gt; {

<span class="hljs-comment">// First, find the user by their ID</span>

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: userId } });

<span class="hljs-keyword">if</span> (!user) {

<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(httpStatus.BAD_REQUEST, <span class="hljs-string">"User doesn't exist"</span>);

}

<span class="hljs-comment">// Update the user with the new details</span>

<span class="hljs-keyword">await</span> User.update(userDetails, { <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: userId } });

<span class="hljs-comment">// Fetch the updated user to return it</span>

<span class="hljs-keyword">const</span> updatedUser = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: userId } });

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Updated user:'</span>, updatedUser); <span class="hljs-comment">// Log the updated user</span>

<span class="hljs-keyword">return</span> updatedUser; <span class="hljs-comment">// Return the updated user object</span>

};
</code></pre>
<p>The update operation aims to modify the data entered in previous operations. That is, to update some data fields.</p>
<p>In the case of Sequelize, the <code>update</code> method is invoked. To succeed with this, the particular user to be edited must be identified. The code above then generates the updated data field and sends it as the output of a successful request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728593828831/33a2bf88-7f4c-4847-b139-e4d97dcd805b.png" alt="A PUT request to edit and update user details endpoint" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-delete-operation">Delete Operation</h3>
<pre><code class="lang-javascript">

<span class="hljs-keyword">const</span> deleteUser = <span class="hljs-keyword">async</span> (userId) =&gt; {

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: userId } });

<span class="hljs-keyword">if</span> (!user) {

<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(httpStatus.BAD_REQUEST, <span class="hljs-string">"User doesn't exist"</span>);

}

<span class="hljs-comment">// Delete the user</span>

<span class="hljs-keyword">await</span> user.destroy();

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Deleted user:'</span>, user); <span class="hljs-comment">// Log the deleted user</span>

<span class="hljs-keyword">return</span> user; <span class="hljs-comment">// Return the deleted user object (useful for confirmation)</span>

};
</code></pre>
<p>The delete operation is invoked when data in the database table needs to be deleted. Sequelize makes provision for this via the use of the <code>destroy</code> method. This method deletes a specific user. When executed, a success response code is displayed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728593876348/ad01b671-5e93-4e34-afbb-dc2a961d576e.png" alt="A DELETE request to remove a particular user detail from the database" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-additional-information">Additional Information</h2>
<p>So far, we have integrated an ORM library to serve as a connection between our backend application and our relational database. We also explored advanced concepts such as database migrations and CRUD operations. To learn more about this, you can explore the documentation and utilize it in building more complex projects, as hands-on learning is much encouraged.</p>
<p>Feel free to reach out to me on my <a target="_blank" href="http://dev.to/oluwatobi2001">blog</a> and check out my other articles <a target="_blank" href="https://linktr.ee/tobilyn77">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work with SQLite in Python – A Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ SQLite is one of the most popular relational database management systems (RDBMS). It’s lightweight, meaning that it doesn’t take up much space on your system. One of its best features is that it’s serverless, so you don’t need to install or manage a ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/work-with-sqlite-in-python-handbook/</link>
                <guid isPermaLink="false">66fd1605986ae3c9e56b8ba4</guid>
                
                    <category>
                        <![CDATA[ SQLite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Wed, 02 Oct 2024 09:44:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727862097228/24433377-ebb8-49b5-b0ee-5736f629399d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>SQLite is one of the most popular relational database management systems (RDBMS). It’s lightweight, meaning that it doesn’t take up much space on your system. One of its best features is that it’s serverless, so you don’t need to install or manage a separate server to use it.</p>
<p>Instead, it stores everything in a simple file on your computer. It also requires zero configuration, so there’s no complicated setup process, making it perfect for beginners and small projects.</p>
<p>SQLite is a great choice for small to medium applications because it’s easy to use, fast, and can handle most tasks that bigger databases can do, but without the hassle of managing extra software. Whether you're building a personal project or prototyping a new app, SQLite is a solid option to get things up and running quickly.</p>
<p>In this tutorial, you'll learn how to work with SQLite using Python. Here’s what we’re going to cover in this tutorial:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-python-environment">How to Set Up Your Python Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-an-sqlite-database">How to Create an SQLite Database</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-database-tables">How to Create Database Tables</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-insert-data-into-a-table">How to Insert Data into a Table</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-query-data">How to Query Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-update-and-delete-data">How to Update and Delete Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-transactions">How to Use Transactions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-sqlite-query-performance-with-indexing">How to Optimize SQLite Query Performance with Indexing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-errors-and-exceptions">How to Handle Errors and Exceptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-export-and-import-data-bonus-section">How to Export and Import Data [Bonus Section]</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<p>This tutorial is perfect for anyone who wants to get started with databases without diving into complex setups.</p>
<h2 id="heading-how-to-set-up-your-python-environment">How to Set Up Your Python Environment</h2>
<p>Before working with SQLite, let’s ensure your Python environment is ready. Here’s how to set everything up.</p>
<h3 id="heading-installing-python">Installing Python</h3>
<p>If you don’t have Python installed on your system yet, you can download it from the official <a target="_blank" href="https://www.python.org/downloads/">Python website</a>. Follow the installation instructions for your operating system (Windows, macOS, or Linux).</p>
<p>To check if Python is installed, open your terminal (or command prompt) and type:</p>
<pre><code class="lang-bash">python --version
</code></pre>
<p>This should show the current version of Python installed. If it’s not installed, follow the instructions on the Python website.</p>
<h3 id="heading-installing-sqlite3-module">Installing SQLite3 Module</h3>
<p>The good news is that SQLite3 comes built-in with Python! You don’t need to install it separately because it’s included in the standard Python library. This means you can start using it right away without any additional setup.</p>
<h3 id="heading-how-to-create-a-virtual-environment-optional-but-recommended">How to Create a Virtual Environment (Optional but Recommended)</h3>
<p>It’s a good idea to create a virtual environment for each project to keep your dependencies organized. A virtual environment is like a clean slate where you can install packages without affecting your global Python installation.</p>
<p>To create a virtual environment, follow these steps:</p>
<ol>
<li><p>First, open your terminal or command prompt and navigate to the directory where you want to create your project.</p>
</li>
<li><p>Run the following command to create a virtual environment:</p>
</li>
</ol>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>Here, <code>env</code> is the name of the virtual environment. You can name it anything you like.</p>
<ol start="3">
<li>Activate the virtual environment:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Use the command for Windows</span>
env\Scripts\activate

<span class="hljs-comment"># Use the command for macOS/Linux:</span>
env/bin/activate
</code></pre>
<p>After activating the virtual environment, you’ll notice that your terminal prompt changes, showing the name of the virtual environment. This means you’re now working inside it.</p>
<h3 id="heading-installing-necessary-libraries">Installing Necessary Libraries</h3>
<p>We’ll need a few additional libraries for this project. Specifically, we’ll use:</p>
<ul>
<li><p><code>pandas</code>: This is an optional library for handling and displaying data in tabular format, useful for advanced use cases.</p>
</li>
<li><p><code>faker</code>: This library will help us generate fake data, like random names and addresses, which we can insert into our database for testing.</p>
</li>
</ul>
<p>To install <code>pandas</code> and <code>faker</code>, simply run the following commands:</p>
<pre><code class="lang-bash">pip install pandas faker
</code></pre>
<p>This installs both <code>pandas</code> and <code>faker</code> into your virtual environment. With this, your environment is set up, and you’re ready to start creating and managing your SQLite database in Python!</p>
<h2 id="heading-how-to-create-an-sqlite-database">How to Create an SQLite Database</h2>
<p>A database is a structured way to store and manage data so that it can be easily accessed, updated, and organized. It’s like a digital filing system that allows you to efficiently store large amounts of data, whether it’s for a simple app or a more complex system. Databases use tables to organize data, with rows and columns representing individual records and their attributes.</p>
<h3 id="heading-how-sqlite-databases-work">How SQLite Databases Work</h3>
<p>Unlike most other database systems, SQLite is a serverless database. This means that it doesn’t require setting up or managing a server, making it lightweight and easy to use. All the data is stored in a single file on your computer, which you can easily move, share, or back up. Despite its simplicity, SQLite is powerful enough to handle many common database tasks and is widely used in mobile apps, embedded systems, and small to medium-sized projects.</p>
<h3 id="heading-how-to-create-a-new-sqlite-database">How to Create a New SQLite Database</h3>
<p>Let’s create a new SQLite database and learn how to interact with it using Python’s <code>sqlite3</code> library.</p>
<h4 id="heading-connecting-to-the-database">Connecting to the Database</h4>
<p>Since <code>sqlite3</code> is pre-installed, you just need to import it in your Python script. To create a new database or connect to an existing one, we use the <code>sqlite3.connect()</code> method. This method takes the name of the database file as an argument. If the file doesn’t exist, SQLite will automatically create it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Connect to the SQLite database (or create it if it doesn't exist)</span>
connection = sqlite3.connect(<span class="hljs-string">'my_database.db'</span>)
</code></pre>
<p>In this example, a file named <code>my_database.db</code> is created in the same directory as your script. If the file already exists, SQLite will just open the connection to it.</p>
<h4 id="heading-creating-a-cursor">Creating a Cursor</h4>
<p>Once you have a connection, the next step is to create a cursor object. The cursor is responsible for executing SQL commands and queries on the database.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a cursor object</span>
cursor = connection.cursor()
</code></pre>
<h4 id="heading-closing-the-connection">Closing the Connection</h4>
<p>After you’ve finished working with the database, it’s important to close the connection to free up any resources. You can close the connection with the following command:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Close the database connection</span>
connection.close()
</code></pre>
<p>However, you should only close the connection once you’re done with all your operations.</p>
<p>When you run your Python script, a file named <code>my_database.db</code> will be created in your current working directory. You’ve now successfully created your first SQLite database!</p>
<h3 id="heading-how-to-use-context-manager-to-open-and-close-connections">How to Use Context Manager to Open and Close Connections</h3>
<p>Python provides a more efficient and cleaner way to handle database connections using the <code>with</code> statement, also known as a context manager. The <code>with</code> statement automatically opens and closes the connection, ensuring that the connection is properly closed even if an error occurs during the database operations. This eliminates the need to manually call <code>connection.close()</code>.</p>
<p>Here’s how you can use the <code>with</code> statement to handle database connections:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Step 1: Use 'with' to connect to the database (or create one) and automatically close it when done</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Step 2: Create a cursor object to interact with the database</span>
    cursor = connection.cursor()

    print(<span class="hljs-string">"Database created and connected successfully!"</span>)

<span class="hljs-comment"># No need to call connection.close(); it's done automatically!</span>
</code></pre>
<p>From now on, we’ll use the <code>with</code> statement in our upcoming code examples to manage database connections efficiently. This will make the code more concise and easier to maintain.</p>
<h2 id="heading-how-to-create-database-tables">How to Create Database Tables</h2>
<p>Now that we’ve created an SQLite database and connected to it, the next step is to create tables inside the database. A table is where we’ll store our data, organized in rows (records) and columns (attributes). For this example, we’ll create a table called <code>Students</code> to store information about students, which we’ll reuse in upcoming sections.</p>
<p>To create a table, we use SQL's <code>CREATE TABLE</code> statement. This command defines the table structure, including the column names and the data types for each column.</p>
<p>Here’s a simple SQL command to create a <code>Students</code> table with the following fields:</p>
<ul>
<li><p><code>id</code>: A unique identifier for each student (an integer).</p>
</li>
<li><p><strong>name</strong>: The student's name (text).</p>
</li>
<li><p><strong>age</strong>: The student's age (an integer).</p>
</li>
<li><p><strong>email</strong>: The student's email address (text).</p>
</li>
</ul>
<p>The SQL command to create this table would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> Students (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span> PRIMARY <span class="hljs-keyword">KEY</span> AUTOINCREMENT,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    age <span class="hljs-built_in">INTEGER</span>,
    email <span class="hljs-built_in">TEXT</span>
);
</code></pre>
<p>We can execute this <code>CREATE TABLE</code> SQL command in Python using the <code>sqlite3</code> library. Let’s see how to do that.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database and automatically close the connection when done</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to create the Students table</span>
    create_table_query = <span class="hljs-string">'''
    CREATE TABLE IF NOT EXISTS Students (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        age INTEGER,
        email TEXT
    );
    '''</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(create_table_query)

    <span class="hljs-comment"># Commit the changes</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">"Table 'Students' created successfully!"</span>)
</code></pre>
<ul>
<li><p><code>IF NOT EXISTS</code>: This ensures that the table is only created if it doesn’t already exist, preventing errors if the table has been created before.</p>
</li>
<li><p><code>connection.commit()</code>: This saves (commits) the changes to the database.</p>
</li>
</ul>
<p>When you run the Python code above, it will create the <code>Students</code> table in the <code>my_database.db</code> database file. You’ll also see a message in the terminal confirming that the table has been created successfully.</p>
<p>If you’re using Visual Studio Code, you can install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=qwtel.sqlite-viewer">SQLite Viewer</a> extension to view SQLite databases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727514353100/522fc6f1-0363-41ca-a76a-b730470cb64a.png" alt="SQLite Viewer - VS Code Extension" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-data-types-in-sqlite-and-their-mapping-to-python">Data Types in SQLite and Their Mapping to Python</h3>
<p>SQLite supports several data types, which we need to understand when defining our tables. Here’s a quick overview of common SQLite data types and how they map to Python types:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>SQLite Data Type</td><td>Description</td><td>Python Equivalent</td></tr>
</thead>
<tbody>
<tr>
<td><strong>INTEGER</strong></td><td>Whole numbers</td><td><code>int</code></td></tr>
<tr>
<td><strong>TEXT</strong></td><td>Text strings</td><td><code>str</code></td></tr>
<tr>
<td><strong>REAL</strong></td><td>Floating-point numbers</td><td><code>float</code></td></tr>
<tr>
<td><strong>BLOB</strong></td><td>Binary data (e.g., images, files)</td><td><code>bytes</code></td></tr>
<tr>
<td><strong>NULL</strong></td><td>Represents no value or missing data</td><td><code>None</code></td></tr>
</tbody>
</table>
</div><p>In our <code>Students</code> table:</p>
<ul>
<li><p><code>id</code> is of type <code>INTEGER</code>, which maps to Python’s <code>int</code>.</p>
</li>
<li><p><code>name</code> and <code>email</code> are of type <code>TEXT</code>, which map to Python’s <code>str</code>.</p>
</li>
<li><p><code>age</code> is also of type <code>INTEGER</code>, mapping to Python’s <code>int</code>.</p>
</li>
</ul>
<h2 id="heading-how-to-insert-data-into-a-table">How to Insert Data into a Table</h2>
<p>Now that we have our <code>Students</code> table created, it’s time to start inserting data into the database. In this section, we’ll cover how to insert both single and multiple records using Python and SQLite, and how to avoid common security issues like SQL injection by using parameterized queries.</p>
<h3 id="heading-how-to-insert-a-single-record">How to Insert a Single Record</h3>
<p>To insert data into the database, we use the <code>INSERT INTO</code> SQL command. Let’s start by inserting a single record into our <code>Students</code> table.</p>
<p>Here’s the basic SQL syntax for inserting a single record:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> Students (<span class="hljs-keyword">name</span>, age, email) 
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'John Doe'</span>, <span class="hljs-number">20</span>, <span class="hljs-string">'johndoe@example.com'</span>);
</code></pre>
<p>However, instead of writing SQL directly in our Python script with hardcoded values, we’ll use parameterized queries to make our code more secure and flexible. Parameterized queries help prevent SQL injection, a common attack where malicious users can manipulate the SQL query by passing harmful input.</p>
<p>Here’s how we can insert a single record into the <code>Students</code> table using a parameterized query:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to open and close the connection automatically</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Insert a record into the Students table</span>
    insert_query = <span class="hljs-string">'''
    INSERT INTO Students (name, age, email) 
    VALUES (?, ?, ?);
    '''</span>
    student_data = (<span class="hljs-string">'Jane Doe'</span>, <span class="hljs-number">23</span>, <span class="hljs-string">'jane@example.com'</span>)

    cursor.execute(insert_query, student_data)

    <span class="hljs-comment"># Commit the changes automatically</span>
    connection.commit()

    <span class="hljs-comment"># No need to call connection.close(); it's done automatically!</span>
    print(<span class="hljs-string">"Record inserted successfully!"</span>)
</code></pre>
<p>The <code>?</code> placeholders represent the values to be inserted into the table. The actual values are passed as a tuple (<code>student_data</code>) in the <code>cursor.execute()</code> method.</p>
<h3 id="heading-how-to-insert-multiple-records">How to Insert Multiple Records</h3>
<p>If you want to insert multiple records at once, you can use the <code>executemany()</code> method in Python. This method takes a list of tuples, where each tuple represents one record.</p>
<p>To make our example more dynamic, we can use the <code>Faker</code> library to generate random student data. This is useful for testing and simulating real-world scenarios.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> faker <span class="hljs-keyword">import</span> Faker
<span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Initialize Faker</span>
fake = Faker([<span class="hljs-string">'en_IN'</span>])

<span class="hljs-comment"># Use 'with' to open and close the connection automatically</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Insert a record into the Students table</span>
    insert_query = <span class="hljs-string">'''
    INSERT INTO Students (name, age, email) 
    VALUES (?, ?, ?);
    '''</span>
    students_data = [(fake.name(), fake.random_int(
        min=<span class="hljs-number">18</span>, max=<span class="hljs-number">25</span>), fake.email()) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">5</span>)]

    <span class="hljs-comment"># Execute the query for multiple records</span>
    cursor.executemany(insert_query, students_data)

    <span class="hljs-comment"># Commit the changes</span>
    connection.commit()

    <span class="hljs-comment"># Print confirmation message</span>
    print(<span class="hljs-string">"Fake student records inserted successfully!"</span>)
</code></pre>
<p>In this code:</p>
<ul>
<li><p><code>Faker()</code> generates random names, ages, and emails for students. Passing the locale(<code>[‘en_IN’]</code>) is optional.</p>
</li>
<li><p><code>cursor.executemany()</code>: This method allows us to insert multiple records at once, making the code more efficient.</p>
</li>
<li><p><code>students_data</code>: A list of tuples where each tuple represents one student’s data.</p>
</li>
</ul>
<h3 id="heading-how-to-handle-common-issues-sql-injection">How to Handle Common Issues: SQL Injection</h3>
<p>SQL injection is a security vulnerability where attackers can insert or manipulate SQL queries by providing harmful input. For example, an attacker might try to inject code like <code>'; DROP TABLE Students; --</code> to delete the table.</p>
<p>By using parameterized queries (as demonstrated above), we avoid this issue. The <code>?</code> placeholders in parameterized queries ensure that input values are treated as data, not as part of the SQL command. This makes it impossible for malicious code to be executed.</p>
<h2 id="heading-how-to-query-data">How to Query Data</h2>
<p>Now that we’ve inserted some data into our <code>Students</code> table, let’s learn how to retrieve the data from the table. We'll explore different methods for fetching data in Python, including <code>fetchone()</code>, <code>fetchall()</code>, and <code>fetchmany()</code>.</p>
<p>To query data from a table, we use the <code>SELECT</code> statement. Here’s a simple SQL command to select all columns from the <code>Students</code> table:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> Students;
</code></pre>
<p>This command retrieves all records and columns from the <code>Students</code> table. We can execute this <code>SELECT</code> query in Python and fetch the results.</p>
<h3 id="heading-how-to-fetch-all-records">How to Fetch All Records</h3>
<p>Here’s how we can fetch all records from the <code>Students</code> table:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch all records</span>
    all_students = cursor.fetchall()

    <span class="hljs-comment"># Display results in the terminal</span>
    print(<span class="hljs-string">"All Students:"</span>)
    <span class="hljs-keyword">for</span> student <span class="hljs-keyword">in</span> all_students:
        print(student)
</code></pre>
<p>In this example, the <code>fetchall()</code> method retrieves all rows returned by the query as a list of tuples.</p>
<pre><code class="lang-bash">All Students:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
(2, <span class="hljs-string">'Bahadurjit Sabharwal'</span>, 18, <span class="hljs-string">'tristanupadhyay@example.net'</span>)
(3, <span class="hljs-string">'Zayyan Arya'</span>, 20, <span class="hljs-string">'yashawinibhakta@example.org'</span>)
(4, <span class="hljs-string">'Hemani Shukla'</span>, 18, <span class="hljs-string">'gaurikanarula@example.com'</span>)
(5, <span class="hljs-string">'Warda Kara'</span>, 20, <span class="hljs-string">'npatil@example.net'</span>)
(6, <span class="hljs-string">'Mitali Nazareth'</span>, 19, <span class="hljs-string">'sparekh@example.org'</span>)
</code></pre>
<h3 id="heading-how-to-fetch-a-single-record">How to Fetch a Single Record</h3>
<p>If you want to retrieve only one record, you can use the <code>fetchone()</code> method:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch one record</span>
    student = cursor.fetchone()

    <span class="hljs-comment"># Display the result</span>
    print(<span class="hljs-string">"First Student:"</span>)
    print(student)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">First Student:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
</code></pre>
<h3 id="heading-how-to-fetch-multiple-records">How to Fetch Multiple Records</h3>
<p>To fetch a specific number of records, you can use <code>fetchmany(size)</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:

    <span class="hljs-comment"># Create a cursor object</span>
    cursor = connection.cursor()

    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Execute the SQL command</span>
    cursor.execute(select_query)

    <span class="hljs-comment"># Fetch three records</span>
    three_students = cursor.fetchmany(<span class="hljs-number">3</span>)

    <span class="hljs-comment"># Display results</span>
    print(<span class="hljs-string">"Three Students:"</span>)
    <span class="hljs-keyword">for</span> student <span class="hljs-keyword">in</span> three_students:
        print(student)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Three Students:
(1, <span class="hljs-string">'Jane Doe'</span>, 23, <span class="hljs-string">'jane@example.com'</span>)
(2, <span class="hljs-string">'Bahadurjit Sabharwal'</span>, 18, <span class="hljs-string">'tristanupadhyay@example.net'</span>)
(3, <span class="hljs-string">'Zayyan Arya'</span>, 20, <span class="hljs-string">'yashawinibhakta@example.org'</span>)
</code></pre>
<h3 id="heading-how-to-use-pandas-for-better-data-presentation">How to Use <code>pandas</code> for Better Data Presentation</h3>
<p>For better data presentation, we can use the <code>pandas</code> library to create a <code>DataFrame</code> from our query results. This makes it easier to manipulate and visualize the data.</p>
<p>Here’s how to fetch all records and display them as a pandas DataFrame:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    <span class="hljs-comment"># Write the SQL command to select all records from the Students table</span>
    select_query = <span class="hljs-string">"SELECT * FROM Students;"</span>

    <span class="hljs-comment"># Use pandas to read SQL query directly into a DataFrame</span>
    df = pd.read_sql_query(select_query, connection)

<span class="hljs-comment"># Display the DataFrame</span>
print(<span class="hljs-string">"All Students as DataFrame:"</span>)
print(df)
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">All Students as DataFrame:
   id                  name  age                        email
0   1              Jane Doe   23             jane@example.com
1   2  Bahadurjit Sabharwal   18  tristanupadhyay@example.net
2   3           Zayyan Arya   20  yashawinibhakta@example.org
3   4         Hemani Shukla   18    gaurikanarula@example.com
4   5            Warda Kara   20           npatil@example.net
5   6       Mitali Nazareth   19          sparekh@example.org
</code></pre>
<p>The <code>pd.read_sql_query()</code> function executes the SQL query and directly returns the results as a pandas DataFrame.</p>
<h2 id="heading-how-to-update-and-delete-data">How to Update and Delete Data</h2>
<p>In this section, we’ll learn how to update existing records and delete records from our <code>Students</code> table using SQL commands in Python. This is essential for managing and maintaining your data effectively.</p>
<h3 id="heading-updating-existing-records">Updating Existing Records</h3>
<p>To modify existing records in a database, we use the SQL <code>UPDATE</code> command. This command allows us to change the values of specific columns in one or more rows based on a specified condition.</p>
<p>For example, if we want to update a student's age, the SQL command would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> Students 
<span class="hljs-keyword">SET</span> age = <span class="hljs-number">21</span> 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'Jane Doe'</span>;
</code></pre>
<p>Now, let’s write Python code to update a specific student's age in our <code>Students</code> table.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># SQL command to update a student's age</span>
    update_query = <span class="hljs-string">'''
    UPDATE Students 
    SET age = ? 
    WHERE name = ?;
    '''</span>

    <span class="hljs-comment"># Data for the update</span>
    new_age = <span class="hljs-number">21</span>
    student_name = <span class="hljs-string">'Jane Doe'</span>

    <span class="hljs-comment"># Execute the SQL command with the data</span>
    cursor.execute(update_query, (new_age, student_name))

    <span class="hljs-comment"># Commit the changes to save the update</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">f"Updated age for <span class="hljs-subst">{student_name}</span> to <span class="hljs-subst">{new_age}</span>."</span>)
</code></pre>
<p>In this example, we used parameterized queries to prevent SQL injection.</p>
<h3 id="heading-how-to-delete-records-from-the-table">How to Delete Records from the Table</h3>
<p>To remove records from a database, we use the SQL <code>DELETE</code> command. This command allows us to delete one or more rows based on a specified condition.</p>
<p>For example, if we want to delete a student named 'Jane Doe', the SQL command would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> Students 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'Jane Doe'</span>;
</code></pre>
<p>Let’s write Python code to delete a specific student from our <code>Students</code> table using the <code>with</code> statement.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Use 'with' to connect to the SQLite database</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># SQL command to delete a student</span>
    delete_query = <span class="hljs-string">'''
    DELETE FROM Students 
    WHERE name = ?;
    '''</span>

    <span class="hljs-comment"># Name of the student to be deleted</span>
    student_name = <span class="hljs-string">'Jane Doe'</span>

    <span class="hljs-comment"># Execute the SQL command with the data</span>
    cursor.execute(delete_query, (student_name,))

    <span class="hljs-comment"># Commit the changes to save the deletion</span>
    connection.commit()

    <span class="hljs-comment"># Print a confirmation message</span>
    print(<span class="hljs-string">f"Deleted student record for <span class="hljs-subst">{student_name}</span>."</span>)
</code></pre>
<h4 id="heading-important-considerations">Important Considerations</h4>
<ul>
<li><p><strong>Conditions</strong>: Always use the <code>WHERE</code> clause when updating or deleting records to avoid modifying or removing all rows in the table. Without a <code>WHERE</code> clause, the command affects every row in the table.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727519069500/f22be4cc-e75f-4492-af01-ed08f31361f3.jpeg" alt="357089 rows affected Meme" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
</li>
<li><p><strong>Backup</strong>: It’s good practice to back up your database before performing updates or deletions, especially in production environments.</p>
</li>
</ul>
<h2 id="heading-how-to-use-transactions">How to Use Transactions</h2>
<p>A transaction is a sequence of one or more SQL operations that are treated as a single unit of work. In the context of a database, a transaction allows you to perform multiple operations that either all succeed or none at all. This ensures that your database remains in a consistent state, even in the face of errors or unexpected issues.</p>
<p>For example, if you are transferring money between two bank accounts, you would want both the debit from one account and the credit to the other to succeed or fail together. If one operation fails, the other should not be executed to maintain consistency.</p>
<h3 id="heading-why-use-transactions">Why Use Transactions?</h3>
<ol>
<li><p><strong>Atomicity</strong>: Transactions ensure that a series of operations are treated as a single unit. If one operation fails, none of the operations will be applied to the database.</p>
</li>
<li><p><strong>Consistency</strong>: Transactions help maintain the integrity of the database by ensuring that all rules and constraints are followed.</p>
</li>
<li><p><strong>Isolation</strong>: Each transaction operates independently of others, preventing unintended interference.</p>
</li>
<li><p><strong>Durability</strong>: Once a transaction is committed, the changes are permanent, even in the event of a system failure.</p>
</li>
</ol>
<h3 id="heading-when-to-use-transactions">When to Use Transactions?</h3>
<p>You should use transactions when:</p>
<ul>
<li><p>Performing multiple related operations that must succeed or fail together.</p>
</li>
<li><p>Modifying critical data that requires consistency and integrity.</p>
</li>
<li><p>Working with operations that can potentially fail, such as financial transactions or data migrations.</p>
</li>
</ul>
<h3 id="heading-how-to-manage-transactions-in-python">How to Manage Transactions in Python</h3>
<p>In SQLite, transactions are managed using the <code>BEGIN</code>, <code>COMMIT</code>, and <code>ROLLBACK</code> commands. However, when using the <code>sqlite3</code> module in Python, you typically manage transactions through the connection object.</p>
<h5 id="heading-starting-a-transaction">Starting a Transaction</h5>
<p>A transaction begins implicitly when you execute any SQL statement. To start a transaction explicitly, you can use the <code>BEGIN</code> command:</p>
<pre><code class="lang-python">cursor.execute(<span class="hljs-string">"BEGIN;"</span>)
</code></pre>
<p>However, it’s usually unnecessary to start a transaction manually, as SQLite starts a transaction automatically when you execute an SQL statement.</p>
<h5 id="heading-how-to-commit-a-transaction">How to Commit a Transaction</h5>
<p>To save all changes made during a transaction, you use the <code>commit()</code> method. This makes all modifications permanent in the database.</p>
<pre><code class="lang-python">connection.commit()
</code></pre>
<p>We have already used the <code>commit()</code> method in the above provided examples.</p>
<h5 id="heading-rolling-back-a-transaction">Rolling Back a Transaction</h5>
<p>If something goes wrong and you want to revert the changes made during a transaction, you can use the <code>rollback()</code> method. This will undo all changes made since the transaction started.</p>
<pre><code class="lang-python">connection.rollback()
</code></pre>
<h3 id="heading-example-of-using-transactions-in-python">Example of Using Transactions in Python</h3>
<p>To illustrate the use of transactions in a real-world scenario, we’ll create a new table called <code>Customers</code> to manage customer accounts. In this example, we’ll assume each customer has a <code>balance</code>. We will add two customers to this table and perform a funds transfer operation between them.</p>
<p>First, let's create the <code>Customers</code> table and insert two customers:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3

<span class="hljs-comment"># Create the Customers table and add two customers</span>
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
    cursor = connection.cursor()

    <span class="hljs-comment"># Create Customers table</span>
    create_customers_table = <span class="hljs-string">'''
    CREATE TABLE IF NOT EXISTS Customers (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL UNIQUE,
        balance REAL NOT NULL
    );
    '''</span>
    cursor.execute(create_customers_table)

    <span class="hljs-comment"># Insert two customers</span>
    cursor.execute(
        <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (<span class="hljs-string">'Ashutosh'</span>, <span class="hljs-number">100.0</span>))
    cursor.execute(
        <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (<span class="hljs-string">'Krishna'</span>, <span class="hljs-number">50.0</span>))

    connection.commit()
</code></pre>
<p>Now, let’s perform the funds transfer operation between Ashutosh and Krishna:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">transfer_funds</span>(<span class="hljs-params">from_customer, to_customer, amount</span>):</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Start a transaction</span>
            cursor.execute(<span class="hljs-string">"BEGIN;"</span>)

            <span class="hljs-comment"># Deduct amount from the sender</span>
            cursor.execute(
                <span class="hljs-string">"UPDATE Customers SET balance = balance - ? WHERE name = ?;"</span>, (amount, from_customer))
            <span class="hljs-comment"># Add amount to the receiver</span>
            cursor.execute(
                <span class="hljs-string">"UPDATE Customers SET balance = balance + ? WHERE name = ?;"</span>, (amount, to_customer))

            <span class="hljs-comment"># Commit the changes</span>
            connection.commit()
            print(
                <span class="hljs-string">f"Transferred <span class="hljs-subst">{amount}</span> from <span class="hljs-subst">{from_customer}</span> to <span class="hljs-subst">{to_customer}</span>."</span>)

        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            <span class="hljs-comment"># If an error occurs, rollback the transaction</span>
            connection.rollback()
            print(<span class="hljs-string">f"Transaction failed: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-comment"># Example usage</span>
transfer_funds(<span class="hljs-string">'Ashutosh'</span>, <span class="hljs-string">'Krishna'</span>, <span class="hljs-number">80.0</span>)
</code></pre>
<p>In this example, we first created a <code>Customers</code> table and inserted two customers, Ashutosh with a balance of ₹100, and Krishna with a balance of ₹50. We then performed a funds transfer of ₹80 from Ashutosh to Krishna. By using transactions, we ensure that both the debit from Ashutosh's account and the credit to Krishna's account are executed as a single atomic operation, maintaining data integrity in the event of any errors. If the transfer fails (for example, due to insufficient funds), the transaction will roll back, leaving both accounts unchanged.</p>
<h2 id="heading-how-to-optimize-sqlite-query-performance-with-indexing">How to Optimize SQLite Query Performance with Indexing</h2>
<p>Indexing is a powerful technique used in databases to improve query performance. An index is essentially a data structure that stores the location of rows based on specific column values, much like an index at the back of a book helps you quickly locate a topic.</p>
<p>Without an index, SQLite has to scan the entire table row by row to find the relevant data, which becomes inefficient as the dataset grows. By using an index, SQLite can jump directly to the rows you need, significantly speeding up query execution.</p>
<h3 id="heading-how-to-populate-the-database-with-fake-data">How to Populate the Database with Fake Data</h3>
<p>To effectively test the impact of indexing, we need a sizable dataset. Instead of manually adding records, we can use the <code>faker</code> library to quickly generate fake data. In this section, we’ll generate 10,000 fake records and insert them into our <code>Students</code> table. This will simulate a real-world scenario where databases grow large, and query performance becomes important.</p>
<p>We will use the <code>executemany()</code> method to insert the records as below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">from</span> faker <span class="hljs-keyword">import</span> Faker

<span class="hljs-comment"># Initialize the Faker library</span>
fake = Faker([<span class="hljs-string">'en_IN'</span>])


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">insert_fake_students</span>(<span class="hljs-params">num_records</span>):</span>
    <span class="hljs-string">"""Generate and insert fake student data into the Students table."""</span>
    fake_data = [(fake.name(), fake.random_int(min=<span class="hljs-number">18</span>, max=<span class="hljs-number">25</span>),
                  fake.email()) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(num_records)]

    <span class="hljs-comment"># Use 'with' to handle the database connection</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Insert fake data into the Students table</span>
        cursor.executemany(<span class="hljs-string">'''
        INSERT INTO Students (name, age, email) 
        VALUES (?, ?, ?);
        '''</span>, fake_data)

        connection.commit()

    print(<span class="hljs-string">f"<span class="hljs-subst">{num_records}</span> fake student records inserted successfully."</span>)


<span class="hljs-comment"># Insert 10,000 fake records into the Students table</span>
insert_fake_students(<span class="hljs-number">10000</span>)
</code></pre>
<p>By running this script, 10,000 fake student records will be added to the <code>Students</code> table. In the next section, we'll query the database and compare the performance of queries with and without indexing.</p>
<h3 id="heading-how-to-query-without-indexes">How to Query Without Indexes</h3>
<p>In this section, we’ll query the <code>Students</code> table without any indexes to observe how SQLite performs when there are no optimizations in place. This will serve as a baseline to compare the performance when we add indexes later.</p>
<p>Without indexes, SQLite performs a full table scan, which means that it must check every row in the table to find matching results. For small datasets, this is manageable, but as the number of records grows, the time taken to search increases dramatically. Let’s see this in action by running a basic <code>SELECT</code> query to search for a specific student by name and measure how long it takes.</p>
<p>First, we’ll query the <code>Students</code> table by looking for a student with a specific name. We’ll log the time taken to execute the query using Python’s <code>time</code> module to measure the performance.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">query_without_index</span>(<span class="hljs-params">search_name</span>):</span>
    <span class="hljs-string">"""Query the Students table by name without an index and measure the time taken."""</span>

    <span class="hljs-comment"># Connect to the database using 'with'</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Measure the start time</span>
        start_time = time.perf_counter_ns()

        <span class="hljs-comment"># Perform a SELECT query to find a student by name</span>
        cursor.execute(<span class="hljs-string">'''
        SELECT * FROM Students WHERE name = ?;
        '''</span>, (search_name,))

        <span class="hljs-comment"># Fetch all results (there should be only one or a few in practice)</span>
        results = cursor.fetchall()

        <span class="hljs-comment"># Measure the end time</span>
        end_time = time.perf_counter_ns()

        <span class="hljs-comment"># Calculate the total time taken</span>
        elapsed_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display the results and the time taken</span>
        print(<span class="hljs-string">f"Query completed in <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.5</span>f}</span> microseconds."</span>)
        print(<span class="hljs-string">"Results:"</span>, results)


<span class="hljs-comment"># Example: Searching for a student by name</span>
query_without_index(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>Here’s the output:</p>
<pre><code class="lang-bash">Query completed <span class="hljs-keyword">in</span> 1578.10000 microseconds.
Results: [(104, <span class="hljs-string">'Ojasvi Dhawan'</span>, 21, <span class="hljs-string">'lavanya26@example.com'</span>)]
</code></pre>
<p>By running the above script, you'll see how long it takes to search the <code>Students</code> table without any indexes. For example, if there are 10,000 records in the table, the query might take 1000-2000 microseconds depending on the size of the table and your hardware. This may not seem too slow for a small dataset, but the performance will degrade as more records are added.</p>
<p>We use <code>time.perf_counter_ns()</code> to measure the time taken for the query execution in nanoseconds. This method is highly accurate for benchmarking small time intervals. We convert the time to microseconds(<code>us</code>) for easier readability.</p>
<h3 id="heading-introducing-the-query-plan">Introducing the Query Plan</h3>
<p>When working with databases, understanding how queries are executed can help you identify performance bottlenecks and optimize your code. SQLite provides a helpful tool for this called <code>EXPLAIN QUERY PLAN</code>, which allows you to analyze the steps SQLite takes to retrieve data.</p>
<p>In this section, we’ll introduce how to use <code>EXPLAIN QUERY PLAN</code> to visualize and understand the inner workings of a query—specifically, how SQLite performs a full table scan when no index is present.</p>
<p>Let’s use <code>EXPLAIN QUERY PLAN</code> to see how SQLite retrieves data from the <code>Students</code> table without any indexes. We’ll search for a student by name, and the query plan will reveal the steps SQLite takes to find the matching rows.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">explain_query</span>(<span class="hljs-params">search_name</span>):</span>
    <span class="hljs-string">"""Explain the query execution plan for a SELECT query without an index."""</span>

    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Use EXPLAIN QUERY PLAN to analyze how the query is executed</span>
        cursor.execute(<span class="hljs-string">'''
        EXPLAIN QUERY PLAN
        SELECT * FROM Students WHERE name = ?;
        '''</span>, (search_name,))

        <span class="hljs-comment"># Fetch and display the query plan</span>
        query_plan = cursor.fetchall()

        print(<span class="hljs-string">"Query Plan:"</span>)
        <span class="hljs-keyword">for</span> step <span class="hljs-keyword">in</span> query_plan:
            print(step)


<span class="hljs-comment"># Example: Analyzing the query plan for searching by name</span>
explain_query(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>When you run this code, SQLite will return a breakdown of how it plans to execute the query. Here’s an example of what the output might look like:</p>
<pre><code class="lang-bash">Query Plan:
(2, 0, 0, <span class="hljs-string">'SCAN Students'</span>)
</code></pre>
<p>This indicates that SQLite is scanning the entire <code>Students</code> table (a full table scan) to find the rows where the <code>name</code> column matches the provided value (<code>Ojasvi Dhawan</code>). Since there is no index on the <code>name</code> column, SQLite must examine each row in the table.</p>
<h3 id="heading-how-to-create-an-index">How to Create an Index</h3>
<p>Creating an index on a column allows SQLite to find rows more quickly during query operations. Instead of scanning the entire table, SQLite can use the index to jump directly to the relevant rows, significantly speeding up queries—especially those involving large datasets.</p>
<p>To create an index, use the following SQL command:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-keyword">index</span>-<span class="hljs-keyword">name</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">table</span> (<span class="hljs-keyword">column</span>(s));
</code></pre>
<p>In this example, we will create an index on the <code>name</code> column of the <code>Students</code> table. Here’s how you can do it using Python:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_index</span>():</span>
    <span class="hljs-string">"""Create an index on the name column of the Students table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># SQL command to create an index on the name column</span>
        create_index_query = <span class="hljs-string">'''
        CREATE INDEX IF NOT EXISTS idx_name ON Students (name);
        '''</span>

        <span class="hljs-comment"># Measure the start time</span>
        start_time = time.perf_counter_ns()

        <span class="hljs-comment"># Execute the SQL command to create the index</span>
        cursor.execute(create_index_query)

        <span class="hljs-comment"># Measure the start time</span>
        end_time = time.perf_counter_ns()

        <span class="hljs-comment"># Commit the changes</span>
        connection.commit()

        print(<span class="hljs-string">"Index on 'name' column created successfully!"</span>)

        <span class="hljs-comment"># Calculate the total time taken</span>
        elapsed_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display the results and the time taken</span>
        print(<span class="hljs-string">f"Query completed in <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.5</span>f}</span> microseconds."</span>)


<span class="hljs-comment"># Call the function to create the index</span>
create_index()
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Index on <span class="hljs-string">'name'</span> column created successfully!
Query completed <span class="hljs-keyword">in</span> 102768.60000 microseconds.
</code></pre>
<p>Even though creating the index takes this long (102768.6 microseconds), it's a one-time operation. You will still get substantial speed-up when running multiple queries. In the following sections, we will query the database again to observe the performance improvements made possible by this index.</p>
<h3 id="heading-how-to-query-with-indexes">How to Query with Indexes</h3>
<p>In this section, we will perform the same <code>SELECT</code> query we executed earlier, but this time we will take advantage of the index we created on the <code>name</code> column of the <code>Students</code> table. We'll measure and log the execution time to observe the performance improvements provided by the index.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> time


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">query_with_index</span>(<span class="hljs-params">student_name</span>):</span>
    <span class="hljs-string">"""Query the Students table using an index on the name column."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># SQL command to select a student by name</span>
        select_query = <span class="hljs-string">'SELECT * FROM Students WHERE name = ?;'</span>

        <span class="hljs-comment"># Measure the execution time</span>
        start_time = time.perf_counter_ns()  <span class="hljs-comment"># Start the timer</span>

        <span class="hljs-comment"># Execute the query with the provided student name</span>
        cursor.execute(select_query, (student_name,))
        result = cursor.fetchall()  <span class="hljs-comment"># Fetch all results</span>

        end_time = time.perf_counter_ns()  <span class="hljs-comment"># End the timer</span>

        <span class="hljs-comment"># Calculate the elapsed time in microseconds</span>
        execution_time = (end_time - start_time) / <span class="hljs-number">1000</span>

        <span class="hljs-comment"># Display results and execution time</span>
        print(<span class="hljs-string">f"Query result: <span class="hljs-subst">{result}</span>"</span>)
        print(<span class="hljs-string">f"Execution time with index: <span class="hljs-subst">{execution_time:<span class="hljs-number">.5</span>f}</span> microseconds"</span>)


<span class="hljs-comment"># Example: Searching for a student by name</span>
query_with_index(<span class="hljs-string">'Ojasvi Dhawan'</span>)
</code></pre>
<p>Here’s what we get in the output:</p>
<pre><code class="lang-bash">Query result: [(104, <span class="hljs-string">'Ojasvi Dhawan'</span>, 21, <span class="hljs-string">'lavanya26@example.com'</span>)]
Execution time with index: 390.70000 microseconds
</code></pre>
<p>We can observe a significant reduction in execution time compared to when the query was performed without an index.</p>
<p>Let’s analyze the query execution plan for the query with the index on the <code>name</code> column of the <code>Students</code> table. If you execute the same script again to explain the query, you’ll get the below output:</p>
<pre><code class="lang-bash">Query Plan:
(3, 0, 0, <span class="hljs-string">'SEARCH Students USING INDEX idx_name (name=?)'</span>)
</code></pre>
<p>The plan now shows that the query uses the index <code>idx_name</code>, significantly reducing the number of rows that need to be scanned, which leads to faster query execution.</p>
<h3 id="heading-comparing-performance-results">Comparing Performance Results</h3>
<p>Now, let's summarize the performance results we obtained when querying with and without indexes.</p>
<h4 id="heading-execution-time-comparison">Execution Time Comparison</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Query Type</td><td>Execution Time (microseconds)</td></tr>
</thead>
<tbody>
<tr>
<td>Without Index</td><td>1578.1</td></tr>
<tr>
<td>With Index</td><td>390.7</td></tr>
</tbody>
</table>
</div><h4 id="heading-performance-improvement-summary">Performance Improvement Summary</h4>
<ul>
<li><p>The query with the index is approximately 4.04 times faster than the query without the index.</p>
</li>
<li><p>The execution time improved by about 75.24% after adding the index.</p>
</li>
</ul>
<h3 id="heading-best-practices-for-using-indexes">Best Practices for Using Indexes</h3>
<p>Indexes can significantly enhance the performance of your SQLite database, but they should be used judiciously. Here are some best practices to consider when working with indexes:</p>
<h4 id="heading-when-and-why-to-use-indexes">When and Why to Use Indexes</h4>
<ol>
<li><p><strong>Frequent Query Columns</strong>: Use indexes on columns that are frequently used in <code>SELECT</code> queries, especially those used in <code>WHERE</code>, <code>JOIN</code>, and <code>ORDER BY</code> clauses. This is because indexing these columns can drastically reduce query execution time.</p>
</li>
<li><p><strong>Uniqueness Constraints</strong>: When you have columns that must hold unique values (like usernames or email addresses), creating an index can enforce this constraint efficiently.</p>
</li>
<li><p><strong>Large Datasets</strong>: For tables with a large number of records, indexes become increasingly beneficial. They enable quick lookups, which is essential for maintaining performance as your data grows.</p>
</li>
<li><p><strong>Composite Indexes</strong>: Consider creating composite indexes for queries that filter or sort by multiple columns. For example, if you often search for students by both <code>name</code> and <code>age</code>, an index on both columns can optimize such queries.</p>
</li>
</ol>
<h4 id="heading-potential-downsides-of-indexes">Potential Downsides of Indexes</h4>
<p>While indexes provide significant advantages, there are some potential downsides:</p>
<ol>
<li><p><strong>Slower Insert/Update Operations</strong>: When you insert or update records in a table with indexes, SQLite must also update the index, which can slow down these operations. This is because each insert or update requires additional overhead to maintain the index structure.</p>
</li>
<li><p><strong>Increased Storage Requirements</strong>: Indexes consume additional disk space. For large tables, the storage cost can be substantial. Consider this when designing your database schema, especially for systems with limited storage resources.</p>
</li>
<li><p><strong>Complex Index Management</strong>: Having too many indexes can complicate database management. It may lead to situations where you have redundant indexes, which can degrade performance rather than enhance it. Regularly reviewing and optimizing your indexes is a good practice.</p>
</li>
</ol>
<p>Indexes are powerful tools for optimizing database queries, but they require careful consideration. Striking a balance between improved read performance and the potential overhead on write operations is key. Here are some strategies for achieving this balance:</p>
<ul>
<li><p><strong>Monitor Query Performance</strong>: Use SQLite’s <code>EXPLAIN QUERY PLAN</code> to analyze how your queries perform with and without indexes. This can help identify which indexes are beneficial and which may be unnecessary.</p>
</li>
<li><p><strong>Regular Maintenance</strong>: Periodically review your indexes and assess whether they are still needed. Remove redundant or rarely used indexes to streamline your database operations.</p>
</li>
<li><p><strong>Test and Evaluate</strong>: Before implementing indexes in a production environment, conduct thorough testing to understand their impact on both read and write operations.</p>
</li>
</ul>
<p>By following these best practices, you can leverage the benefits of indexing while minimizing potential drawbacks, ultimately enhancing the performance and efficiency of your SQLite database.</p>
<h2 id="heading-how-to-handle-errors-and-exceptions">How to Handle Errors and Exceptions</h2>
<p>In this section, we’ll discuss how to handle errors and exceptions when working with SQLite in Python. Proper error handling is crucial for maintaining the integrity of your database and ensuring that your application behaves predictably.</p>
<h3 id="heading-common-errors-in-sqlite-operations">Common Errors in SQLite Operations</h3>
<p>When interacting with an SQLite database, several common errors may arise:</p>
<ol>
<li><p><strong>Constraint Violations</strong>: This occurs when you try to insert or update data that violates a database constraint, such as primary key uniqueness or foreign key constraints. For example, trying to insert a duplicate primary key will trigger an error.</p>
</li>
<li><p><strong>Data Type Mismatches</strong>: Attempting to insert data of the wrong type (for example, inserting a string where a number is expected) can lead to an error.</p>
</li>
<li><p><strong>Database Locked Errors</strong>: If a database is being written to by another process or connection, trying to access it can result in a "database is locked" error.</p>
</li>
<li><p><strong>Syntax Errors</strong>: Mistakes in your SQL syntax will result in errors when you try to execute your commands.</p>
</li>
</ol>
<h3 id="heading-how-to-use-pythons-exception-handling">How to Use Python's Exception Handling</h3>
<p>Python’s built-in <a target="_blank" href="https://blog.ashutoshkrris.in/exception-handling-in-python">exception handling</a> mechanisms (<code>try</code> and <code>except</code>) are essential for managing errors in SQLite operations. By using these constructs, you can catch exceptions and respond appropriately without crashing your program.</p>
<p>Here’s a basic example of how to handle errors when inserting data into the database:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_customer_with_error_handling</span>(<span class="hljs-params">name, balance</span>):</span>
    <span class="hljs-string">"""Add a new customer with error handling."""</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
            cursor = connection.cursor()
            cursor.execute(
                <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (name, balance))
            connection.commit()
            print(<span class="hljs-string">f"Added customer: <span class="hljs-subst">{name}</span> with balance: <span class="hljs-subst">{balance}</span>"</span>)

    <span class="hljs-keyword">except</span> sqlite3.IntegrityError <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"Error: Integrity constraint violated - <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">except</span> sqlite3.OperationalError <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"Error: Operational issue - <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">f"An unexpected error occurred: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-comment"># Example usage</span>
add_customer_with_error_handling(<span class="hljs-string">'Vishakha'</span>, <span class="hljs-number">100.0</span>)  <span class="hljs-comment"># Valid</span>
add_customer_with_error_handling(<span class="hljs-string">'Vishakha'</span>, <span class="hljs-number">150.0</span>)  <span class="hljs-comment"># Duplicate entry</span>
</code></pre>
<p>In this example:</p>
<ul>
<li><p>We catch <code>IntegrityError</code>, which is raised for violations like unique constraints.</p>
</li>
<li><p>We catch <code>OperationalError</code> for general database-related issues (like database locked errors).</p>
</li>
<li><p>We also have a generic <code>except</code> block to handle any unexpected exceptions.</p>
</li>
</ul>
<p>Output:</p>
<pre><code class="lang-bash">Added customer: Vishakha with balance: 100.0
Error: Integrity constraint violated - UNIQUE constraint failed: Customers.name
</code></pre>
<h3 id="heading-best-practices-for-ensuring-database-integrity">Best Practices for Ensuring Database Integrity</h3>
<ol>
<li><p><strong>Use Transactions</strong>: Always use transactions (as discussed in the previous section) when performing multiple related operations. This helps ensure that either all operations succeed or none do, maintaining consistency.</p>
</li>
<li><p><strong>Validate Input Data</strong>: Before executing SQL commands, validate the input data to ensure it meets the expected criteria (for example, correct types, within allowable ranges).</p>
</li>
<li><p><strong>Catch Specific Exceptions</strong>: Always catch specific exceptions to handle different types of errors appropriately. This allows for clearer error handling and debugging.</p>
</li>
<li><p><strong>Log Errors</strong>: Instead of just printing errors to the console, consider logging them to a file or monitoring system. This will help you track issues in production.</p>
</li>
<li><p><strong>Graceful Degradation</strong>: Design your application to handle errors gracefully. If an operation fails, provide meaningful feedback to the user rather than crashing the application.</p>
</li>
<li><p><strong>Regularly Backup Data</strong>: Regularly back up your database to prevent data loss in case of critical failures or corruption.</p>
</li>
<li><p><strong>Use Prepared Statements</strong>: Prepared statements help prevent SQL injection attacks and can also provide better performance for repeated queries.</p>
</li>
</ol>
<h2 id="heading-how-to-export-and-import-data-bonus-section">How to Export and Import Data [Bonus Section]</h2>
<p>In this section, we will learn how to export data from an SQLite database to common formats like CSV and JSON, as well as how to import data into SQLite from these formats using Python. This is useful for data sharing, backup, and integration with other applications.</p>
<h3 id="heading-exporting-data-from-sqlite-to-csv">Exporting Data from SQLite to CSV</h3>
<p>Exporting data to a CSV (Comma-Separated Values) file is straightforward with Python’s built-in libraries. CSV files are widely used for data storage and exchange, making them a convenient format for exporting data.</p>
<p>Here’s how to export data from an SQLite table to a CSV file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">import</span> csv

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">export_to_csv</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Export data from the Customers table to a CSV file."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Execute a query to fetch all customer data</span>
        cursor.execute(<span class="hljs-string">"SELECT * FROM Customers;"</span>)
        customers = cursor.fetchall()

        <span class="hljs-comment"># Write data to CSV</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'w'</span>, newline=<span class="hljs-string">''</span>) <span class="hljs-keyword">as</span> csv_file:
            csv_writer = csv.writer(csv_file)
            csv_writer.writerow([<span class="hljs-string">'ID'</span>, <span class="hljs-string">'Name'</span>, <span class="hljs-string">'Balance'</span>])  <span class="hljs-comment"># Writing header</span>
            csv_writer.writerows(customers)  <span class="hljs-comment"># Writing data rows</span>

        print(<span class="hljs-string">f"Data exported successfully to <span class="hljs-subst">{file_name}</span>."</span>)

<span class="hljs-comment"># Example usage</span>
export_to_csv(<span class="hljs-string">'customers.csv'</span>)
</code></pre>
<h3 id="heading-how-to-export-data-to-json">How to Export Data to JSON</h3>
<p>Similarly, you can export data to a <a target="_blank" href="https://blog.ashutoshkrris.in/a-beginners-guide-to-the-json-module-in-python">JSON</a> (JavaScript Object Notation) file, which is a popular format for data interchange, especially in web applications.</p>
<p>Here’s an example of how to export data to JSON:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">export_to_json</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Export data from the Customers table to a JSON file."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Execute a query to fetch all customer data</span>
        cursor.execute(<span class="hljs-string">"SELECT * FROM Customers;"</span>)
        customers = cursor.fetchall()

        <span class="hljs-comment"># Convert data to a list of dictionaries</span>
        customers_list = [{<span class="hljs-string">'ID'</span>: customer[<span class="hljs-number">0</span>], <span class="hljs-string">'Name'</span>: customer[<span class="hljs-number">1</span>],
                           <span class="hljs-string">'Balance'</span>: customer[<span class="hljs-number">2</span>]} <span class="hljs-keyword">for</span> customer <span class="hljs-keyword">in</span> customers]

        <span class="hljs-comment"># Write data to JSON</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> json_file:
            json.dump(customers_list, json_file, indent=<span class="hljs-number">4</span>)

        print(<span class="hljs-string">f"Data exported successfully to <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
export_to_json(<span class="hljs-string">'customers.json'</span>)
</code></pre>
<h3 id="heading-how-to-import-data-into-sqlite-from-csv">How to Import Data into SQLite from CSV</h3>
<p>You can also import data from a CSV file into an SQLite database. This is useful for populating your database with existing datasets.</p>
<p>Here's how to import data from a CSV file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">import_from_csv</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Import data from a CSV file into the Customers table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Open the CSV file for reading</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> csv_file:
            csv_reader = csv.reader(csv_file)
            next(csv_reader)  <span class="hljs-comment"># Skip the header row</span>

            <span class="hljs-comment"># Insert each row into the Customers table</span>
            <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> csv_reader:
                cursor.execute(
                    <span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (row[<span class="hljs-number">1</span>], row[<span class="hljs-number">2</span>]))

        connection.commit()
        print(<span class="hljs-string">f"Data imported successfully from <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
import_from_csv(<span class="hljs-string">'customer_data.csv'</span>)
</code></pre>
<h3 id="heading-how-to-import-data-into-sqlite-from-json">How to Import Data into SQLite from JSON</h3>
<p>Similarly, importing data from a JSON file is simple. You can read the JSON file and insert the data into your SQLite table.</p>
<p>Here's how to do it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> sqlite3


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">import_from_json</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-string">"""Import data from a JSON file into the Customers table."""</span>
    <span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">'my_database.db'</span>) <span class="hljs-keyword">as</span> connection:
        cursor = connection.cursor()

        <span class="hljs-comment"># Open the JSON file for reading</span>
        <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> json_file:
            customers_list = json.load(json_file)

            <span class="hljs-comment"># Insert each customer into the Customers table</span>
            <span class="hljs-keyword">for</span> customer <span class="hljs-keyword">in</span> customers_list:
                cursor.execute(<span class="hljs-string">"INSERT INTO Customers (name, balance) VALUES (?, ?);"</span>, (customer[<span class="hljs-string">'Name'</span>], customer[<span class="hljs-string">'Balance'</span>]))

        connection.commit()
        print(<span class="hljs-string">f"Data imported successfully from <span class="hljs-subst">{file_name}</span>."</span>)


<span class="hljs-comment"># Example usage</span>
import_from_json(<span class="hljs-string">'customer_data.json'</span>)
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>And that’s a wrap! This guide has introduced you to the fundamentals of working with SQLite in Python, covering everything from setting up your environment to querying and manipulating data, as well as exporting and importing information. I hope you found it helpful and that it has sparked your interest in using SQLite for your projects.</p>
<p>Now it's time to put your newfound knowledge into practice! I encourage you to create your project using SQLite and Python. Whether it’s a simple application for managing your library, a budgeting tool, or something unique, the possibilities are endless.</p>
<p>Once you’ve completed your project, share it on Twitter and tag me! I’d love to see what you’ve created and celebrate your accomplishments.</p>
<p>You can find all the code from this tutorial on <a target="_blank" href="https://github.com/ashutoshkrris/sqlite-tutorial">GitHub</a>. Thank you for following along, and happy coding!</p>
<blockquote>
<p>Generate Table of Contents for your freeCodeCamp articles for free using the <a target="_blank" href="https://toc-generator.ashutoshkrris.in/freecodecamp">TOC Generator</a> tool.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Full Stack Development with Next.js, Clerk, and Neon Postgres ]]>
                </title>
                <description>
                    <![CDATA[ Full stack development is constantly evolving, with new developer tools and products being introduced that allow us to build secure and reliable applications more efficiently. In this tutorial, I’ll walk you through how to build highly performant web... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/nextjs-clerk-neon-fullstack-development/</link>
                <guid isPermaLink="false">66c375561784344f009b632f</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ankur Tyagi ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jul 2024 15:31:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/Orange---Yellow-Gradient-Make-Design-Blog-Banner--77-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Full stack development is constantly evolving, with new developer tools and products being introduced that allow us to build secure and reliable applications more efficiently.</p>
<p>In this tutorial, I’ll walk you through how to build highly performant web applications with <a target="_blank" href="https://neon.tech">Neon – a serverless PostgreSQL</a> database designed for the cloud. You'll also learn how to perform CRUD (Create, Read, Update, and Delete) operations with Neon.</p>
<p>By the end of this tutorial, you will have the basic knowledge required to start building advanced and scalable web applications with Neon.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents:</strong></h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-neon">What is Neon?</a></li>
<li><a class="post-section-overview" href="#heading-why-neon">Why Neon?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-neon-to-a-nextjs-app">How to add Neon to a Next.js app</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-neon-serverless-driver-with-drizzle-orm-in-nextjs">How to set up Neon Serverless Driver with Drizzle ORM in Next.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-application-interface-with-nextjs">How to Build the Application Interface with Next.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-authenticate-users-with-clerk">How to Authenticate Users with Clerk</a></li>
<li><a class="post-section-overview" href="#heading-crud-operations-with-the-neon-database">CRUD Operations with the Neon Database</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
<li><a class="post-section-overview" href="#heading-next-steps">Next Steps</a></li>
</ul>
<h2 id="heading-what-is-neon">What is Neon?</h2>
<p><a target="_blank" href="https://github.com/neondatabase/neon">Neon</a> is an open-source, scalable, and efficient Postgres DB that separates compute from storage. This means that database computation processes (queries, transactions, and so on) are handled by one set of resources (compute), while the data itself is stored on a separate set of resources (storage). </p>
<p>This architecture allows for greater scalability and performance, making Neon a solid choice for modern web applications.</p>
<p><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXcT4hh-liS2uYYcatl8jC6h9gFqArEw113_WaPzoTFxeps_G97JIVhJKVSQq5DC52NJ0GOoQm4sYL5QhyLhC_e_xocDjSp7iks6j8kv6WSnhRzLVy8TxftshzFnwK238QuVsGdnnBpL_nLDmXju3klwlB6T?key=4GdX_KHTwBEvJEyZsT7b3Q" alt="Neon - a serverless Postgres database" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://neon.tech">Neon - a serverless Postgre</a>s database</em></p>
<h3 id="heading-3-things-to-remember-about-neon">3 Things to Remember About Neon:</h3>
<ul>
<li>🐘 <strong>Postgres</strong>: Neon is built on the foundation of Postgres. It supports the same extensions, drivers, and SQL syntax as Postgres, ensuring familiarity and ease of use.</li>
<li>☁️ <strong>Serverless</strong>: Neon operates on a serverless model. Your database is represented as a simple URL, and Neon automatically scales up and down based on workload demands. Say goodbye to over-provisioning.</li>
<li>🌱 <strong>Branching</strong>: Just like version control for code, Neon allows you to create instant, isolated copies of your data. This feature is invaluable for development, testing, and maintaining separate environments.</li>
</ul>
<h2 id="heading-why-neon">Why Neon?</h2>
<p>Neon brings the serverless experience to Postgres. Developers can build faster and scale their products effortlessly, without the need to dedicate big teams or big budgets to the database.</p>
<p>Neon supports <a target="_blank" href="https://neon.tech/docs/introduction#framework-and-language-quickstarts">multiple languages and frameworks</a> – but what are the unique features that make Neon stand out?</p>
<h3 id="heading-instant-branching-and-auto-scaling">Instant branching and auto-scaling</h3>
<p><a target="_blank" href="https://neon.tech/blog/why-you-want-a-database-that-scales-to-zero">Neon</a> allows you to <a target="_blank" href="https://neon.tech/branching">create database branches instantly</a> for testing, development, and staging environments. This lets you experiment without affecting the production database. </p>
<p>It also provides an <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">auto-scaling capability</a> that automatically adjusts resources based on the application's workload, ensuring optimal performance and cost-efficiency.</p>
<p><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXc1HSzmptXUYsu49JPbWSizwp64G-JVME-7kmmwSKNYLcc1wUmwWXvBa6kuVxncpyazqSPgj_N4ABZddjNG2rDTHE8MFIGm3yKy1DPpiV6C7GZ1tOcTzOFkvtDwpleeJZC--V4efudtYnPe-XKs8K2P740R?key=4GdX_KHTwBEvJEyZsT7b3Q" alt="Neon DB Main Branch Dashboard" width="600" height="400" loading="lazy">
<em>Neon DB Main Dashboard</em></p>
<h3 id="heading-support-for-ai-applications">Support for AI applications</h3>
<p>Neon <a target="_blank" href="https://neon.tech/ai">supports AI and machine learning applications</a> by providing a high-performance and scalable infrastructure. It enables you to perform semantic and similarity searches in Postgres and handles complex queries and large datasets efficiently, making it ideal for AI or LLM applications.</p>
<h3 id="heading-open-source">Open-source</h3>
<p>Neon is backed by a <a target="_blank" href="https://github.com/neondatabase/neon">vibrant community</a> of Postgres hackers, systems engineers, and cloud engineers who are all huge fans of Postgres. </p>
<p>As an open-source platform, Neon offers transparency and flexibility. You can also reach out to the team and contributors to ask questions, contribute, and help improve the software.</p>
<h3 id="heading-serverless-architecture">Serverless Architecture</h3>
<p><a target="_blank" href="https://neon.tech/blog/architecture-decisions-in-neon">Neon</a> eliminates the need for manual server management, allowing you to focus on building applications rather than maintaining infrastructure. Its serverless nature provides on-demand scalability, ensuring that your application can handle varying loads without manual intervention.</p>
<h3 id="heading-built-upon-postgres">Built upon Postgres</h3>
<p>Postgres is one of the most reliable open-source relational <a target="_blank" href="https://neon.tech/blog/get-page-at-lsn">database</a> systems. Neon inherits all the advanced features, stability, and performance optimizations of Postgres, including support for ACID transactions, advanced SQL, and NoSQL/JSON, to create a cheaper and more efficient database for cloud environments.</p>
<h2 id="heading-how-to-add-neon-to-a-nextjs-app">How to Add Neon to a Next.js App</h2>
<p>Neon supports multiple frameworks and libraries and provides clear and detailed documentation on adding Neon to them. The Neon serverless driver enables us to connect and interact with Neon in a Next.js application.</p>
<p>Before we proceed, let’s <a target="_blank" href="https://neon.tech/docs/guides/nextjs">create a Neon account and project</a>.</p>
<p><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXeLMMmCdF3yK_mflMt4mqz3woiTLibcrGCMK5-AE1f2KftVKYduH39BybuVdu68G2am8uwDWHJUyisFittXeqCmcgxNyhcZXIiXHjxIIu-eymmM_-VVdAMW0LWTVA7NrXI-QXNEYso3Sj1FrLX0tvSP6yNK?key=4GdX_KHTwBEvJEyZsT7b3Q" alt="Neon DB Projects Overview" width="600" height="400" loading="lazy">
<em>Neon DB Projects Overview: View and manage all your projects in one place.</em></p>
<p>Within your project dashboard, you'll find a database connection string. You'll use this to interact with your Neon database.</p>
<p><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXfpIPj10xMleoJEKIMFghRGp2ofgC0zJEA0C2ExMr2ijz673RM_45Kuh1RXVKkEn_uW-hU6-YIPd35C73gYMZtN_7lvChQ4MSK47CIWovh8MyUzRQluguEhAEXdvRZ8wxpOLINIyVfp50u1gIOf3foBAzg3?key=4GdX_KHTwBEvJEyZsT7b3Q" alt="Neon DB Project Dashboard" width="600" height="400" loading="lazy">
<em>Neon DB Project Dashboard: Manage database settings with ease from the project dashboard.</em></p>
<p>Create a TypeScript Next.js project by running the following code snippet in your terminal:</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>npx create-next-app neon-blog-with-clerk</span></p></td></tr></tbody></table>

<p>Next, install the Neon Serverless package:</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>npm install @neondatabase/serverless</span></p></td></tr></tbody></table>

<p>Create a .env.local file and copy your database connection string into the file:</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>NEON_DATABASE_URL=</span><span>"postgres://&lt;user&gt;:&lt;password&gt;@&lt;endpoint_hostname&gt;.neon.tech:&lt;port&gt;/&lt;dbname&gt;?sslmode=require"</span></p></td></tr></tbody></table>

<p>Create a 'db' folder containing an index.ts file within the Next.js app directory and copy the code snippet below into the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { neon } <span class="hljs-keyword">from</span> <span class="hljs-string">'@neondatabase/serverless'</span>;

<span class="hljs-keyword">if</span> (!process.env.NEON_DATABASE_URL) {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'NEON_DATABASE_URL must be a Neon postgres connection string'</span>)
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getDBVersion = <span class="hljs-keyword">async</span>() =&gt; {
    <span class="hljs-keyword">const</span> sql = neon(process.env.NEON_DATABASE_URL!);
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> sql<span class="hljs-string">`SELECT version()`</span>;
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">version</span>: response[<span class="hljs-number">0</span>].version }
}
</code></pre>
<p>Convert the app/page.tsx file to a server component and execute the <code>getDBVersion()</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getDBVersion } <span class="hljs-keyword">from</span> <span class="hljs-string">"./db"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { version } = <span class="hljs-keyword">await</span> getDBVersion();
    <span class="hljs-built_in">console</span>.log({version})

   <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{/** — UI elements — */}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>)

}
</code></pre>
<p>The <code>getDBVersion()</code> function establishes a connection with the Neon database and allows us to run SQL queries using the Postgres client. This function returns the database version, which is then logged to the console.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>{</span><span><br></span><span>&nbsp; version: </span><span>'PostgreSQL 16.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit'</span><span><br></span><span>}</span></p></td></tr></tbody></table>

<p>Congratulations – you’ve successfully added Neon to your Next.js application.</p>
<p>But interacting with the Neon database by writing SQL queries directly can require extra learning or introduce complexities for developers who are not familiar with SQL. It can also lead to errors or performance issues when performing complex queries. </p>
<p>This is why Neon supports database ORMs such as Drizzle ORM, which provide a higher-level interface for interacting with the database. <a target="_blank" href="https://orm.drizzle.team/docs/overview">Drizzle ORM</a> enables you to write complex query functions and interact with the database easily using TypeScript.</p>
<h2 id="heading-how-to-set-up-neon-serverless-driver-with-drizzle-orm-in-nextjs">How to Set Up Neon Serverless Driver with Drizzle ORM in Next.js</h2>
<p><a target="_blank" href="https://orm.drizzle.team/docs/overview">Drizzle ORM</a> lets you query data and perform various operations on the database using simple TypeScript query commands. It is lightweight, typesafe, and easy to use.</p>
<p>First, you'll need to install the <a target="_blank" href="https://orm.drizzle.team/kit-docs/overview">Drizzle Kit</a> and the <a target="_blank" href="https://orm.drizzle.team/docs/overview">Drizzle ORM</a> package.</p>
<p>Drizzle Kit lets you manage the database schema and migrations.</p>
<pre><code class="lang-bash">npm i drizzle-orm
npm i -D drizzle-kit
</code></pre>
<p>Inside the db folder, add an actions.ts, and schema.ts file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> db
touch actions.ts schema.ts
</code></pre>
<p>Add the code snippet below into the db/schema.ts file. It contains the database schema.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {  text, serial, pgTable, timestamp } <span class="hljs-keyword">from</span> <span class="hljs-string">"drizzle-orm/pg-core"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> postsTable = pgTable(<span class="hljs-string">"posts"</span>, {
    <span class="hljs-attr">id</span>: serial(<span class="hljs-string">"id"</span>).primaryKey().notNull(),
    <span class="hljs-attr">content</span>: text(<span class="hljs-string">"content"</span>).notNull(),
    <span class="hljs-attr">author</span>: text(<span class="hljs-string">"author"</span>).notNull(),
    <span class="hljs-attr">author_id</span>: text(<span class="hljs-string">"author_id"</span>).notNull(),
    <span class="hljs-attr">title</span>: text(<span class="hljs-string">"title"</span>).notNull(),
    <span class="hljs-attr">created_at</span>: timestamp(<span class="hljs-string">"created_at"</span>).defaultNow(),
    <span class="hljs-attr">slug</span>: text(<span class="hljs-string">"slug"</span>).notNull(),
});
</code></pre>
<p>Update the db/index.ts file to connect to the Neon database and export the Drizzle instance (db). This will be used to execute typesafe SQL queries against your Postgres database hosted by Neon.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { neon } <span class="hljs-keyword">from</span> <span class="hljs-string">'@neondatabase/serverless'</span>;
<span class="hljs-keyword">import</span> { drizzle } <span class="hljs-keyword">from</span> <span class="hljs-string">'drizzle-orm/neon-http'</span>;
<span class="hljs-keyword">import</span> { postsTable } <span class="hljs-keyword">from</span> <span class="hljs-string">'./schema'</span>;


<span class="hljs-keyword">if</span> (!process.env.NEON_DATABASE_URL) {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'DATABASE_URL must be a Neon postgres connection string'</span>)
}
<span class="hljs-keyword">const</span> sql = neon(process.env.NEON_DATABASE_URL!);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> db = drizzle(sql, {
  <span class="hljs-attr">schema</span>: { postsTable }
});
</code></pre>
<p>Next, create a drizzle.config.ts file at the root of the Next.js folder and add the following configuration:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> type { Config } <span class="hljs-keyword">from</span> <span class="hljs-string">'drizzle-kit'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;

dotenv.config();

<span class="hljs-keyword">if</span> (!process.env.NEON_DATABASE_URL) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'NEON DATABASE_URL not found in environment'</span>);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">schema</span>: <span class="hljs-string">'./src/app/db/schema.ts'</span>,
  <span class="hljs-attr">out</span>: <span class="hljs-string">'./src/app/db/migrations'</span>,
 <span class="hljs-attr">dialect</span>: <span class="hljs-string">"postgresql"</span>,
  <span class="hljs-attr">dbCredentials</span>: {
    <span class="hljs-attr">url</span>: process.env.NEON_DATABASE_URL,
 },
  <span class="hljs-attr">strict</span>: <span class="hljs-literal">true</span>,
} satisfies Config;
</code></pre>
<p>The drizzle.config.ts file contains all the information about your database connection, migration folder, and schema files. </p>
<p>Finally, update the package.json file to include the Drizzle Kit commands for generating database migrations and updating the tables.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>{</span><span><br></span><span> "scripts" : {</span><span><br></span><span>&nbsp; "migrate": </span><span>"npx drizzle-kit generate -- dotenv_config_path='.env.local'"</span><span>,</span><span><br></span><span>&nbsp; "db-create": </span><span>"npx drizzle-kit push -- dotenv_config_path='.env.local'"</span><span><br></span><span> }</span><span><br></span><span>}</span></p></td></tr></tbody></table>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-8.png" alt="Neon DB Tables Dashboard" width="600" height="400" loading="lazy">
<em>Neon DB Tables Dashboard: Effortlessly manage your database tables and view all data.</em></p>
<h2 id="heading-how-to-build-the-application-interface-with-nextjs">How to Build the Application Interface with Next.js</h2>
<p>In this section, you’ll learn how to build a blog application that allows users to read posts and authenticate authors, enabling them to create and delete posts from the Neon database. </p>
<p>The application is divided into 3 pages:</p>
<ul>
<li>Home Page: displays all the available blog posts.</li>
<li>Post Details Page (/posts/[slug]): displays the content of a particular blog post.</li>
<li>Create Post Page (/posts/create): allows authors to create new blog posts.</li>
</ul>
<p>Install the following packages:</p>
<pre><code class="lang-javascript">npm install date-fns react-simplemde-editor easymde react-markdown remark-gfm dotenv
</code></pre>
<p>The <a target="_blank" href="https://github.com/date-fns/date-fns">Date Fns package</a> allows us to convert the posts' timestamps to human-readable forms for display within the application. The <a target="_blank" href="https://www.npmjs.com/package/react-simplemde-editor">React SimpleMDE Editor</a> provides a WYSIWYG editor for creating content in markdown formats using an interactive editor, and the <a target="_blank" href="https://www.npmjs.com/package/react-markdown">React Markdown package</a> converts the markdown texts to their corresponding plain formats.</p>
<p>Next, create a utils.ts file within the Next.js app folder and copy the code snippet below into the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { format } <span class="hljs-keyword">from</span> <span class="hljs-string">"date-fns"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> formatDateString = (dateString: <span class="hljs-built_in">Date</span> | <span class="hljs-literal">null</span>): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (!dateString) <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
    <span class="hljs-keyword">const</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(dateString);
    <span class="hljs-keyword">const</span> formattedDate = format(date, <span class="hljs-string">"MMMM do yyyy, h:mma"</span>);
    <span class="hljs-keyword">return</span> formattedDate;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> slugifySentences = (sentence: string): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> slug = sentence
 .toLowerCase()
 .replace(<span class="hljs-regexp">/[^a-z0-9\s-]/g</span>, <span class="hljs-string">""</span>)
 .replace(<span class="hljs-regexp">/\s+/g</span>, <span class="hljs-string">"-"</span>);

    <span class="hljs-comment">// Generate 5 random letters</span>
    <span class="hljs-keyword">const</span> randomLetters = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">5</span> }, <span class="hljs-function">() =&gt;</span>
        <span class="hljs-built_in">String</span>.fromCharCode(<span class="hljs-number">97</span> + <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">26</span>))
 ).join(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${slug}</span>-<span class="hljs-subst">${randomLetters}</span>`</span>;
};
</code></pre>
<p>The <code>formatDateString</code> function accepts a Date object and returns the date and time in a human-readable format using the date-fns package. The <code>slugifySentences</code> function creates a slug for each post using the post's title, which is useful for implementing the routes for each post.</p>
<p>Copy the code snippet below into the app/page.tsx file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> { formatDateString, slugifySentences } <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils"</span>;

interface Post {
    <span class="hljs-attr">author_id</span>: string;
    title: string;
    content: string;
    author: string;
    slug: string;
    id: number | <span class="hljs-literal">null</span>;
    created_at: <span class="hljs-built_in">Date</span> | <span class="hljs-literal">null</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// dummy posts</span>
    <span class="hljs-keyword">const</span> posts: Post[] = [
        {
            <span class="hljs-attr">author_id</span>: <span class="hljs-string">"1"</span>,
            <span class="hljs-attr">title</span>: <span class="hljs-string">"Welcome to Neon Tutorial"</span>,
            <span class="hljs-attr">content</span>: <span class="hljs-string">"This is a test post"</span>,
            <span class="hljs-attr">author</span>: <span class="hljs-string">"John Doe"</span>,
            <span class="hljs-attr">slug</span>: slugifySentences(<span class="hljs-string">"Welcome to Neon Tutorial"</span>),
            <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">created_at</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        },
        {
            <span class="hljs-attr">author_id</span>: <span class="hljs-string">"1"</span>,
            <span class="hljs-attr">title</span>: <span class="hljs-string">"Hello World"</span>,
            <span class="hljs-attr">content</span>: <span class="hljs-string">"This is a test post"</span>,
            <span class="hljs-attr">author</span>: <span class="hljs-string">"Jane Doe"</span>,
            <span class="hljs-attr">slug</span>: slugifySentences(<span class="hljs-string">"Hello World"</span>),
            <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">created_at</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        },
    ];

    <span class="hljs-comment">// shorten posts with longer title</span>
    <span class="hljs-keyword">const</span> shortenText = (text: string): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
        <span class="hljs-keyword">return</span> text.length &lt;= <span class="hljs-number">55</span> ? text : text.slice(<span class="hljs-number">0</span>, <span class="hljs-number">55</span>) + <span class="hljs-string">"..."</span>;
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'md:px-8 py-8 px-4 w-full bg-white'</span>&gt;</span>
                {posts?.map((post) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                        <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">posts</span>/${<span class="hljs-attr">post.slug</span>}`}
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'rounded w-full border-[1px] p-4 text-blue-500 hover:bg-blue-50 hover:drop-shadow-md transition-all duration-200 ease-in-out flex items-center justify-between gap-4 mb-4'</span>
                        <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>
                    &gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-lg font-semibold'</span>&gt;</span>{shortenText(post.title)}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'flex items-center justify-between'</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-xs text-gray-500'</span>&gt;</span>
                                {formatDateString(post?.created_at)}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>The app/page.tsx file represents the home page of the application and displays all the available posts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-5.png" alt="blog-app" width="600" height="400" loading="lazy">
<em>It's live - see the power of serverless PostgreSQL and Next.js</em></p>
<p>Next, add the routes for creating posts and reading the contents of each post. Within the Next.js app folder, create a posts directory containing /posts/create and /posts/[slug] subdirectories.</p>
<p>Create a page.tsx file within the /posts/create folder and copy the code snippet below into the file:</p>
<pre><code class="lang-javascript">use client<span class="hljs-string">";
import { useState, useCallback } from "</span>react<span class="hljs-string">";
import { useRouter } from "</span>next/navigation<span class="hljs-string">";
import SimpleMDE from "</span>react-simplemde-editor<span class="hljs-string">";
import "</span>easymde/dist/easymde.min.css<span class="hljs-string">";
import { slugifySentences } from "</span>@/app/utils<span class="hljs-string">";

export default function PostCreate() {
    const [publishing, setPublishing] = useState&lt;boolean&gt;(false);
    const [content, setContent] = useState&lt;string&gt;("</span><span class="hljs-string">");
    const [title, setTitle] = useState&lt;string&gt;("</span><span class="hljs-string">");
    const router = useRouter();

    const onChangeContent = useCallback((value: string) =&gt; {
        setContent(value);
    }, []);

    const handleCreatePost = async (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {
        e.preventDefault();
        console.log({ title, content });
        router.push("</span>/<span class="hljs-string">");
    };

    return (
        &lt;div className='min-h-[100vh]'&gt;
            &lt;main className='md:px-8 py-8 px-4 w-full'&gt;
                &lt;form className='flex flex-col w-full' onSubmit={handleCreatePost}&gt;
                    &lt;label htmlFor='title' className='text-sm text-blue-600'&gt;
                        Title
                    &lt;/label&gt;
                    &lt;input
                        type='text'
                        name='title'
                        id='title'
                        value={title}
                        required
                        onChange={(e) =&gt; setTitle(e.target.value)}
                        className='px-4 py-3 border-2 rounded-md text-lg mb-4'
                    /&gt;

                    &lt;label htmlFor='content' className='text-sm text-blue-600'&gt;
                        Content
                    &lt;/label&gt;
                    &lt;SimpleMDE value={content} onChange={onChangeContent} id='content' /&gt;

                    &lt;button
                        type='submit'
                        disabled={publishing}
                        className='bg-blue-600 mt-2 text-white py-3 rounded-md'
                    &gt;
                        {publishing ? "</span>Publishing....please wait<span class="hljs-string">" : "</span>Publish Post<span class="hljs-string">"}
                    &lt;/button&gt;
                &lt;/form&gt;
            &lt;/main&gt;
        &lt;/div&gt;
    );
}</span>
</code></pre>
<p>The /posts/create page renders a form that accepts the title and content of the post, allowing authors to create new blog posts.</p>
<p><img src="https://lh7-us.googleusercontent.com/docsz/AD_4nXed0zewJjjPH6pDp2z4E1dZ-F2d717R5LJuqqrqC-8pzv_PAHcNWem1q_19NgnpUoM9hgBa7MhHtFs0fn_kaEMQOXaRHGPPdoIi1qiOovdTbiPSPlut1EX3Yo-2APt3wvwW08K2BrjJ6rx-R3EDEdxfyNwu?key=4GdX_KHTwBEvJEyZsT7b3Q" alt="How to Create a Post in Blog App" width="600" height="400" loading="lazy">
<em>Create your next blog post with ease</em></p>
<p>Finally, update the /posts/[slug] page to display each post's content and include a button that allows only the posts' authors to delete posts. (You'll learn how to implement this later in the tutorial.)</p>
<pre><code class="lang-javascript">use client<span class="hljs-string">";
import { useRouter, useParams } from "</span>next/navigation<span class="hljs-string">";
import ReactMarkdown from "</span>react-markdown<span class="hljs-string">";
import { useEffect, useState, useCallback } from "</span>react<span class="hljs-string">";
import remarkGfm from "</span>remark-gfm<span class="hljs-string">";
import { formatDateString } from "</span>@/app/utils<span class="hljs-string">";

export default function Post() {
    const router = useRouter();
    const [loading, setLoading] = useState&lt;boolean&gt;(true);
    const [post, setPost] = useState&lt;Post | null&gt;(null);
    const params = useParams&lt;{ slug: string }&gt;();

    const deletePost = async () =&gt; {
        if (confirm("</span>Are you sure you want to <span class="hljs-keyword">delete</span> <span class="hljs-built_in">this</span> post?<span class="hljs-string">")) {
            alert(`Delete ${params.slug}`);
            router.push("</span>/<span class="hljs-string">");
        }
    };

    return (
        &lt;div&gt;
            &lt;main className='w-full md:px-8 px-4'&gt;
                &lt;header className='mb-6 py-4'&gt;
                    &lt;div className='flex items-center justify-between mb-2'&gt;
                        &lt;h2 className='text-3xl text-blue-700 font-bold'&gt;{post?.title}&lt;/h2&gt;

                        &lt;div className='flex items-center'&gt;
                            &lt;button
                                className='px-4 py-2 rounded text-xs bg-red-200 hover:bg-red-40 mr-3'
                                onClick={() =&gt; deletePost()}
                            &gt;
                                Delete
                            &lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;

                    &lt;div className='flex'&gt;
                        &lt;p className='text-red-500 mr-8 text-sm'&gt;
                            Author: &lt;span className='text-gray-700'&gt;{post?.author}&lt;/span&gt;
                        &lt;/p&gt;
                        &lt;p className='text-red-500 mr-6 text-sm'&gt;
                            Posted on:{"</span> <span class="hljs-string">"}
                            &lt;span className='text-gray-700'&gt;
                                {formatDateString(post?.created_at!)}
                            &lt;/span&gt;
                        &lt;/p&gt;
                    &lt;/div&gt;
                &lt;/header&gt;

                &lt;div className='text-sm text-justify'&gt;
                    &lt;ReactMarkdown remarkPlugins={[remarkGfm]}&gt;
                        {post?.content!}
                    &lt;/ReactMarkdown&gt;
                &lt;/div&gt;
            &lt;/main&gt;
        &lt;/div&gt;
    );
}</span>
</code></pre>
<p>The /posts/[slug] page accepts the unique slug for each blog post, fetches the post's content, and allows post authors to delete their own posts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-4.png" alt="Blog Post " width="600" height="400" loading="lazy">
<em>Blog Post</em></p>
<p>Congratulations! You've completed the user interface for the application.</p>
<h2 id="heading-how-to-authenticate-users-with-clerk">How to Authenticate Users with Clerk</h2>
<p><a target="_blank" href="https://github.com/clerkinc">Clerk</a> is a complete user management platform that enables you to add various forms of authentication to your software applications. It provides easy-to-use, flexible UI components and APIs that can be integrated seamlessly into your application.</p>
<p>Install the <a target="_blank" href="https://clerk.com/docs/quickstarts/nextjs">Clerk Next.js SDK</a> by running the following code snippet in your terminal.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>npm install @clerk/nextjs</span></p></td></tr></tbody></table>

<p>Create a middleware.ts file within the Next.js src folder and copy the code snippet below into the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { clerkMiddleware, createRouteMatcher } <span class="hljs-keyword">from</span> <span class="hljs-string">"@clerk/nextjs/server"</span>;


<span class="hljs-comment">// the createRouteMatcher function accepts an array of routes to be protected</span>
<span class="hljs-keyword">const</span> protectedRoutes = createRouteMatcher([<span class="hljs-string">"/posts/create"</span>]);

<span class="hljs-comment">// protects the route</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> clerkMiddleware(<span class="hljs-function">(<span class="hljs-params">auth, req</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (protectedRoutes(req)) {
        auth().protect();
 }
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
    <span class="hljs-attr">matcher</span>: [<span class="hljs-string">"/((?!.*\\..*|_next).*)"</span>, <span class="hljs-string">"/"</span>, <span class="hljs-string">"/(api|trpc)(.*)"</span>],
};
</code></pre>
<p>The <code>createRouteMatcher</code> function accepts an array containing routes to be protected from unauthenticated users and the <code>clerkMiddleware()</code> function ensures the routes are protected.</p>
<p>Next, import the following Clerk components into the app/layout.tsx file and update the RootLayout function as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
    ClerkProvider,
    SignInButton,
    SignedIn,
    SignedOut,
    UserButton,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@clerk/nextjs"</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{
    children,
}: {
    children: React.ReactNode;
}</span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ClerkProvider</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">'en'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{inter.className}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'w-full py-4 border-b-[1px] md:px-8 px-4 text-center flex items-center justify-between sticky top-0 bg-white z-10 '</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">'/'</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-xl font-extrabold text-blue-700'</span>&gt;</span>
                            Neon Blog
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'flex items-center gap-5'</span>&gt;</span>
                            {/*-- if user is signed out --*/}
                            <span class="hljs-tag">&lt;<span class="hljs-name">SignedOut</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">SignInButton</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">'modal'</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">SignedOut</span>&gt;</span>
                            {/*-- if user is signed in --*/}
                            <span class="hljs-tag">&lt;<span class="hljs-name">SignedIn</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">'/posts/create'</span> <span class="hljs-attr">className</span>=<span class="hljs-string">''</span>&gt;</span>
                                    Create Post
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">UserButton</span> <span class="hljs-attr">showName</span> /&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">SignedIn</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>

                    {children}
                <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">ClerkProvider</span>&gt;</span></span>
    );
}
</code></pre>
<p>When a user is not signed in, the <a target="_blank" href="https://clerk.com/docs/components/unstyled/sign-in-button">Sign in button</a> component is rendered. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-3.png" alt="Clerk UI" width="600" height="400" loading="lazy">
<em>Seamless sign-ups redefined with Clerk UI</em></p>
<p>Then, after signing into the application, the Clerk <a target="_blank" href="https://clerk.com/docs/components/user/user-button">User Button component</a> and a link to create a new post are displayed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-17.png" alt="Clerk's User Button component" width="600" height="400" loading="lazy">
<em>After sign-in: Use Clerk's User Button to create a new post</em></p>
<p>Next, create a <a target="_blank" href="https://clerk.com/">Clerk account</a> and add a new application project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-7.png" alt="Clerk's sleek UI dashboard" width="600" height="400" loading="lazy">
<em>Clerk's sleek UI dashboard</em></p>
<p>Select username as the authentication method and create the Clerk project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-6.png" alt="clerk-dashboard" width="600" height="400" loading="lazy">
<em>Clerk's sleek UI dashboard</em></p>
<p>Finally, add your Clerk publishable and secret keys into the .env.local file.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=&lt;your_publishable_key&gt;</span><span><br></span><span>CLERK_SECRET_KEY=&lt;your_secret_key&gt;</span></p></td></tr></tbody></table>

<p>Clerk provides various ways to <a target="_blank" href="https://clerk.com/docs/references/nextjs/read-session-data">read user's data</a> on the client and the server, which is essential for identifying users within the application.</p>
<h2 id="heading-crud-operations-with-the-neon-database">CRUD Operations with the Neon Database</h2>
<p>In this section, you’ll learn how to perform CRUD (Create, Read, Update, Delete) operations with the Neon database. These fundamental operations are essential for interacting with and managing data within any application. </p>
<p>The db/actions.ts file will contain the CRUD operations. Add the following code snippet to the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { db } <span class="hljs-keyword">from</span> <span class="hljs-string">"."</span>;
<span class="hljs-keyword">import</span> { postsTable } <span class="hljs-keyword">from</span> <span class="hljs-string">'./schema'</span>;
<span class="hljs-keyword">import</span> { desc, eq } <span class="hljs-keyword">from</span> <span class="hljs-string">"drizzle-orm"</span>;

<span class="hljs-comment">// add a new row to the posts table</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createPost = <span class="hljs-keyword">async</span> (post: Post) =&gt; {
    <span class="hljs-keyword">await</span> db.insert(postsTable).values({
        <span class="hljs-attr">content</span>: post.content,
        <span class="hljs-attr">author</span>: post.author,
        <span class="hljs-attr">author_id</span>: post.author_id,
        <span class="hljs-attr">title</span>: post.title,
        <span class="hljs-attr">slug</span>: post.slug,
    });
};

<span class="hljs-comment">// get all the posts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllPosts = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> db.select().from(postsTable).orderBy(desc(postsTable.created_at));
};

<span class="hljs-comment">// get a post using its slug</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getSinglePost = <span class="hljs-keyword">async</span> (slug: string) =&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> db.query.postsTable.findFirst({
        <span class="hljs-attr">where</span>: <span class="hljs-function">(<span class="hljs-params">post, { eq }</span>) =&gt;</span> eq(post.slug, slug)
    });
};

<span class="hljs-comment">// delete a post</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id: number) =&gt; {
    <span class="hljs-keyword">await</span> db.delete(postsTable).where(eq(postsTable.id, id));
};

<span class="hljs-comment">// update a post's content</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updatePost = <span class="hljs-keyword">async</span> (content: string, <span class="hljs-attr">id</span>: number) =&gt; {
    <span class="hljs-keyword">await</span> db.update(postsTable)
        .set({ <span class="hljs-attr">content</span>: content })
        .where(eq(postsTable.id, id));
};
</code></pre>
<p>From the code snippet above:</p>
<ul>
<li>This <code>createPost</code> function takes a post object as an argument and inserts a new row into the <code>postsTable</code> with the specified post content, author, author ID, title, and slug.</li>
<li>The <code>getAllPosts</code> function retrieves all the posts from the <code>postsTable</code> and sorts them in descending order by their creation date (created_at).</li>
<li>This <code>getSinglePost</code> function takes a slug as an argument and retrieves the first post that matches the given slug from the <code>postsTable</code>. The slug is unique, so it will return a single object.</li>
<li>This <code>deletePost</code> function takes an id as an argument and deletes the post with the matching ID from the <code>postsTable</code>.</li>
<li>This <code>updatePost</code> function accepts <code>content</code> and a post's <code>id</code> as arguments and updates the post's content with the matching ID in the <code>postsTable</code>.</li>
</ul>
<p>Finally, you can execute the CRUD functions on the server via API endpoints or <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch">Next.js server fetch requests</a>. </p>
<p>For instance, you can fetch all the existing blog posts within the Neon database and display them within the application using the Next.js server data fetching method:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getAllPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"./db/actions"</span>;

<span class="hljs-keyword">const</span> getPosts = <span class="hljs-keyword">async</span> () =&gt; <span class="hljs-keyword">await</span> getAllPosts()

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> getPosts()

    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{/** -- UI elements --*/}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>)
}
</code></pre>
<p>You can also create a Next.js API endpoint that returns all the available blog posts. Create a /api/posts/all endpoint that returns the posts:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app/db/actions"</span>;
<span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">POST</span>(<span class="hljs-params"></span>) </span>{


    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getPosts()
        <span class="hljs-keyword">return</span> NextResponse.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Post fetched"</span>, data }, { <span class="hljs-attr">status</span>: <span class="hljs-number">200</span> });
 } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> NextResponse.json(
 { <span class="hljs-attr">message</span>: <span class="hljs-string">"Post not available"</span>, err },
 { <span class="hljs-attr">status</span>: <span class="hljs-number">400</span> }
 );
 }
}
</code></pre>
<p>Congratulations! You’ve completed the project for this tutorial.</p>
<p>You can find the code for the app we built <a target="_blank" href="https://github.com/tyaga001/serverless-postgres-nextjs-handbook">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you’ve learned what a Neon database is, how to create one, and how to perform CRUD operations with Neon and Drizzle ORM in a Next.js application.</p>
<p>Neon's serverless architecture, combined with its scalability and performance optimizations, makes it an excellent choice for modern web applications. Neon also provides a smooth developer experience and a community of passionate individuals ready to help you achieve your application goals. Thank you for reading.</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>By now, you should have a good understanding of how to build full-stack applications with Neon and Next.js.</p>
<p>If you'd like to learn more about how you can leverage Neon to build advanced and scalable applications, you can check out the following resources:</p>
<ul>
<li><a target="_blank" href="https://neon.tech/docs/introduction">Neon documentation</a></li>
<li><a target="_blank" href="https://github.com/neondatabase/examples">Neon example projects</a></li>
<li><a target="_blank" href="https://neon.tech/docs/guides/vercel">How to integrate Neon with Vercel</a></li>
<li><a target="_blank" href="https://neon.tech/docs/import/import-from-postgres">How to import your data from a Postgres database to Neon</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/j4Vak4J10KU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>That's it for this tutorial. I hope you learned something new today.</p>
<p>If you did, please share so that it reaches others as well.</p>
<p>You can connect with me on <a target="_blank" href="https://twitter.com/TheAnkurTyagi">Twitter</a> or subscribe to my <a target="_blank" href="https://bytesizedbets.com/">newsletter</a>. </p>
<h3 id="heading-want-to-read-more-interesting-blog-posts"><strong>Want to read more interesting blog posts?</strong></h3>
<p>You can read more tutorials like this one on my <strong><a target="_blank" href="https://theankurtyagi.com/">blog</a>.</strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Your Database – Optimization Principles and Best Practices ]]>
                </title>
                <description>
                    <![CDATA[ Databases are an integral component of building applications, whether web, desktop or mobile. They symbolically serve as the mitochondria of the application, as their primary function is to manage data. Database management is a critical skill a devel... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/database-optimization-principles/</link>
                <guid isPermaLink="false">66bb58c3965d5c9ed5487ba2</guid>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Fri, 10 May 2024 15:21:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/Acid.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Databases are an integral component of building applications, whether web, desktop or mobile. They symbolically serve as the mitochondria of the application, as their primary function is to manage data.</p>
<p>Database management is a critical skill a developer must possess in building scalable applications that have a high level of efficiency. If not handled properly, it can result in data loss and mismanagement on the part of the database developer.</p>
<p>Hence, databases must be structured and built with the users in mind and built utilizing the best practices available.</p>
<p>This article aims to highlight general principles of database best practices and also explain each peculiarity. But before we discuss that in detail, let’s review what database transactions are all about.</p>
<h2 id="heading-what-are-database-transactions">What are Database Transactions?</h2>
<p>Database transactions are simply groups of operations which can be termed as a unit of a work process performed on a database within a database management system. </p>
<p>It encompasses basic operations such as CRUD operations to more advanced operations such as database indexing, caching, and normalization.</p>
<p>With so many users performing many transactions at the same time, it’s important to ensure that the database is concurrency-enabled to prevent data interference between two or more users accessing the same resource. </p>
<p>Hence, there is the need for the ACID principle.  What then does ACID represent?</p>
<ul>
<li>Atomicity</li>
<li>Consistency</li>
<li>Isolation</li>
<li>Durability</li>
</ul>
<p>Subsequently, we will be discussing each point in detail. First on our list is atomicity.</p>
<h2 id="heading-what-is-the-database-atomicity-principle">What is the Database Atomicity Principle?</h2>
<p>What does database atomicity entail? The atomicity of a database simply means that a database operation can’t be broken down further as a unit. This means that the database operation or transactions gets executed completely, and in case any error comes up during the execution process, the entire operation gets completely cancelled, preventing room for partial operation execution.</p>
<p>If the database isn’t atomic, this can result in the provision of misleading incomplete data and ultimately result in entire system chaos. How does the database ensure atomicity? It does this by creating a copy of the existing database before the operation gets executed and then initiates a crash recovery and backup restoration operation in the event of an operation failure.</p>
<p>It is also important to note that other database principles such as consistency and durability rely on the need for the database to be atomic to be truly fulfilled.</p>
<p>Having discussed this, let’s move on to the database consistency principle.</p>
<h2 id="heading-what-is-the-database-consistency-principle">What is the Database Consistency Principle?</h2>
<p>This principle entails that the database has certain constraints, cascades, triggers and other requirements in place, which needs to be fulfilled while making changes to an established database. Failure to fulfill this requirement will lead to consistency errors, returning the database to its previous stable state.</p>
<p>Also, consistency as a principle ensures that the data updated by a user is made available as the latest version of the data in the database to all users who desire to read the database. Having this in place eliminates the occurrence of inconsistencies and aids faster information retrieval.</p>
<p>Understanding what it means for a database to be consistent involves ensuring the operation performed on the database passes the integrity check before being successfully executed. Having exhausted this in detail, let's discuss the database isolation principle.</p>
<h2 id="heading-what-is-the-database-isolation-principle">What is the Database Isolation Principle?</h2>
<p>Why should we isolate a database and how does one make a database operation independent from other database operations?</p>
<p>Isolation is necessary in a database management system to ensure that the user's access to information on the database is not interfered with by other concurrent transactions undertaken by other users on the database. To enforce this, the use of isolation levels in each database operation helps to preserve information integrity.</p>
<p>To effectively guarantee the database integrity, specific database isolation levels must be used. Here are some of the isolation levels ranked in order of hierarchy:</p>
<ul>
<li>Read uncommitted</li>
<li>Read committed</li>
<li>Repeatable read</li>
<li>Serializability</li>
</ul>
<h3 id="heading-read-uncommitted-isolation-level">Read Uncommitted Isolation Level</h3>
<p>The read uncommitted database isolation level allows other users to have access to read current database transactions which has not yet been completely or successfully executed. It allows access to read what is being referred to as dirty read, which is one of the data inconsistencies that can be seen. This level of data isolation isn’t advised.</p>
<h3 id="heading-read-committed-isolation-level">Read Committed Isolation Level</h3>
<p>This database isolation level disallows other users to read or have access to a database transaction that has not yet been committed. Hence it prevents other users from seeing, updating or overwriting it until it has been completely executed.</p>
<h3 id="heading-repeatable-read-isolation-level">Repeatable Read Isolation Level</h3>
<p>This isolation level exclusively isolates a transaction from other transactions occurring concurrently, preventing other users access to read and update the transactions.</p>
<h3 id="heading-serializability-isolation-level">Serializability Isolation Level</h3>
<p>This is the highest level of data isolation and is referred to as the strictest level. It isolates the multiple transactions performed concurrently and executes them efficiently as they are executed serially. It also prevents database inconsistencies.</p>
<p>Without these levels in place, inconsistent database mishaps such as dirty reads, non-repeatable reads, phantom reads and many others may be experienced. With this, let's move on to the last point about database durability and discuss it in detail.</p>
<h2 id="heading-what-is-the-database-durability-principle">What is the Database Durability Principle?</h2>
<p>What does it imply when we describe a database as durable and how do we ensure the durability of a database? Durability as it sounds is a principle which ensures that databases have a high level of immortality.</p>
<p>Irrespective of any adverse outcomes that the database management system might face such as outages and crashes, there shouldn't be any loss of database information.</p>
<p>How do databases try to achieve this? The database creates a transactional log that contains the recorded data before any new operation gets executed. In the event of any of these adverse events, the transaction log serves as the backup store, ensuring that the database info is well preserved up to the point before the operation occurred, thereby mitigating against data breaches and loss.</p>
<p>We'll also highlight other helpful database operations best practices that can also be implemented.</p>
<h2 id="heading-other-database-operations-best-practices">Other Database Operations Best Practices</h2>
<p>The BASE principle, which is more suited for NoSQL databases such as MongoDB, Redis, and Cassandra, and so on. It entails a database to be:</p>
<ul>
<li>Basically available</li>
<li>Existing in a soft state</li>
<li>And be eventually consistent.</li>
</ul>
<h3 id="heading-basically-available">Basically Available</h3>
<p>This entails that the database prioritizes the availability of the database operations over consistency and concurrency. This is quite applicable to distributed systems which rely on a high level of efficiency to function effectively.</p>
<h3 id="heading-soft-state">Soft State</h3>
<p>This ensures easy flexibility of the database, allowing for size scaling, operations and increased concurrency for optimal database performance at all times. This allows the data to maintain resiliency.</p>
<h3 id="heading-eventually-consistent">Eventually Consistent</h3>
<p>This entails that, irrespective of how the transactions get executed in the sequences, it eventually achieves efficient consistency. This is achieved by conflict resolution and reconciliation. This eventually contributes to the building of a resilient data system.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With this, we have come to the end of the tutorial. We hope you’ve learned essentially about optimizing database operations and their efficiency using the ACID principle and other best practices available.</p>
<p>Feel free to drop comments and questions in the box below, and also check out my other articles <a target="_blank" href="https://www.freecodecamp.org/news/p/2a9a2ef7-b659-4655-97ce-fea0f3a9f668/linktr.ee/tobilyn77">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Run a Postgres Database in Azure Kubernetes Service and Integrate it with a Node.js Express Application ]]>
                </title>
                <description>
                    <![CDATA[ Hey everyone! Today, you're going to learn about deploying a Postgres container in Azure Kubernetes Service (AKS) and connecting it to a Node.js application. In this fast-paced development landscape, deploying via containers, particularly with Kubern... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-run-postgres-in-kubernetes/</link>
                <guid isPermaLink="false">66d45dd851f567b42d9f8435</guid>
                
                    <category>
                        <![CDATA[ containerization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayomide Wilfred Adeyemi ]]>
                </dc:creator>
                <pubDate>Wed, 08 May 2024 20:43:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/Azure-K8s-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey everyone! Today, you're going to learn about deploying a Postgres container in Azure Kubernetes Service (AKS) and connecting it to a Node.js application.</p>
<p>In this fast-paced development landscape, deploying via containers, particularly with Kubernetes, is becoming increasingly popular. Some companies perform numerous deployments daily, so it's crucial for you to learn these technologies.</p>
<p>Kubernetes is a popular choice to deploy containerized applications like web servers, databases, and APIs. You can set up Kubernetes either locally or in the cloud. In this tutorial, we'll explore setting up Kubernetes on a cloud platform, specifically Azure.</p>
<p>I'll walk you through the process of setting up Kubernetes using Azure Kubernetes Service (AKS). You'll configure your YAML file using StatefulSet, Persistent Volume, and Services to deploy a PostgreSQL database on Azure Kubernetes. Then, you'll obtain the PostgreSQL database credentials running inside the AKS and use them to establish a connection with a Node.js application.</p>
<p>We'll cover key concepts such as deployment, stateful sets, persistent volumes, and services, preparing you to deploy a Postgres container effectively on AKS. I'll also help you connect your Node.js Express app to the Postgres container within the AKS cluster.</p>
<p>So find a comfortable seat and get ready, as we're about to dive in.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before you begin, it's important to understand some basic concepts in <a target="_blank" href="https://kubernetes.io">Kubernetes</a> like <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/">pods</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">deployments</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/">services</a>, and <a target="_blank" href="https://kubernetes.io/docs/concepts/architecture/nodes/">nodes</a>.</p>
<p>If you're new to this, I recommend checking out the Stashchuk freeCodeCamp <a target="_blank" href="https://www.youtube.com/watch?v=d6WC5n9G_sM">video</a> for a beginner-friendly tutorial.</p>
<p>You'll also need an active <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">Azure</a> account and subscription to follow along.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#challenges-were-trying-to-solve">Challenges We're Trying to Solve</a><br>  – <a class="post-section-overview" href="#heading-deployments">Deployments</a><br>  – <a class="post-section-overview" href="#heading-statefulsets">StatefulSets</a><br>  – <a class="post-section-overview" href="#heading-persistent-volumes">Persistent Volumes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-azure-kubernetes-service-aks">Azure Kubernetes Service (AKS)</a><br>  – <a class="post-section-overview" href="#heading-step-1-sign-in-to-your-azure-portal">Sign in to Your Azure Portal</a><br>  – <a class="post-section-overview" href="#heading-step-2-create-a-resource">Create a Resource</a><br>  – <a class="post-section-overview" href="#heading-step-3-create-a-new-container">Create a new container</a><br>  – <a class="post-section-overview" href="#heading-step-4-create-a-new-azure-kubernetes-service-aks">Create a new Azure Kubernetes Service(AKS)</a><br>  – <a class="post-section-overview" href="#heading-step-5-create-a-new-resource-group">Create a new resource group</a><br>  – <a class="post-section-overview" href="#heading-step-6-give-your-kubernetes-cluster-a-name">Give your Kubernetes cluster a name</a><br>  – <a class="post-section-overview" href="#heading-step-7-navigate-to-the-node-pool-page">Navigate to the node pool page</a><br>  – <a class="post-section-overview" href="#heading-step-8-enable-container-logs-and-set-up-alerts">Enable container logs and set up alerts</a><br>  – <a class="post-section-overview" href="#heading-step-9-advanced-section">Advanced Section</a><br>  – <a class="post-section-overview" href="#heading-step-10-tags">Tags</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-connect-to-your-aks-cluster-using-the-command-line">Connect to Your AKS Cluster</a><br>  – <a class="post-section-overview" href="#heading-download-azure-cli-and-kubectl">Download Azure CLI and kubectl</a><br>  – <a class="post-section-overview" href="#heading-verify-if-the-azure-cli-is-installed-by-typing-the-command-az-version">Verify if Azure CLI is installed</a><br>  – <a class="post-section-overview" href="#heading-verify-if-kubectl-is-installed">Verify if kubectl is installed</a><br>  – <a class="post-section-overview" href="#heading-login-to-your-azure-account">Login to Azure account</a><br>  – <a class="post-section-overview" href="#heading-configure-kubectl-to-connect-to-your-azure-kubernetes">Configure kubectl</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-resources-with-yaml">How to Create Resources with YAML</a><br>  – <a class="post-section-overview" href="#heading-clone-the-repository">Clone the Repository</a><br>  – <a class="post-section-overview" href="#heading-open-the-cloned-repository-in-any-text-editor">Open the Repository</a><br>  – <a class="post-section-overview" href="#heading-install-project-dependencies">Install Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-yaml-configuration">YAML Configuration</a><br>  – <a class="post-section-overview" href="#heading-storageclass">StorageClass</a><br>  – <a class="post-section-overview" href="#heading-persistentvolumeclaim">PersistentVolumeClaim</a><br>  – <a class="post-section-overview" href="#heading-configmap">ConfigMap</a><br>  – <a class="post-section-overview" href="#heading-statefulset">StatefulSet</a><br>  – <a class="post-section-overview" href="#heading-service">Service</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-yaml-resource-to-azure-kubernetes-service-aks">How to Deploy YAML Resource to Azure</a><br>  – <a target="_blank" href="https://www.freecodecamp.org/news/p/a37cba54-1e70-4fb6-99d4-d9ee63e66e1b/deploy-the-yaml-resource">Deploy the YAML resource</a></p>
</li>
<li><p><a class="post-section-overview" href="#nodejs-application">Node.js Application</a><br>  – <a class="post-section-overview" href="#heading-configure-your-nodejs-application">Configure Nodejs</a><br>  – <a class="post-section-overview" href="#heading-run-your-nodejs-application">Run Nodejs Application</a><br>  – <a class="post-section-overview" href="#heading-test-the-application">Test the Application</a><br>  – <a class="post-section-overview" href="#heading-open-your-postman-application">Open Postman</a><br>  – <a class="post-section-overview" href="#heading-confirm-the-data">Confirm the Data</a><br>  – <a class="post-section-overview" href="#heading-delete-the-pod-to-confirm-data-persistence">Delete Pod</a><br>  – <a class="post-section-overview" href="#heading-data-persistence">Data Persistence</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-challenges-were-trying-to-solve">Challenges We're Trying to Solve</h2>
<p>Firstly, what is Kubernetes? Well, it's like a manager for your software containers. It helps you run and manage lots of containers like web servers, databases, microservices, and APIs which are like little packages holding your applications.</p>
<p>Kubernetes takes care of things like starting, stopping, and scaling these containers, so your apps run smoothly even when there is more load on your application. It's popular because it makes running software in the cloud easier and more reliable.</p>
<p>Now, let's talk about how to tackle some challenges you might face with a real-world application running Postgres in a Kubernetes production cluster.</p>
<p>Imagine that the infrastructure hosting your Postgres crashes, causing you to lose all the services and data stored in the database. Or, picture a scenario where the Postgres database becomes corrupted, leading to data loss.</p>
<p>In both cases, you need a way to back up your application so you can restore it to a working state if disaster strikes.</p>
<p>So, how do you capture a comprehensive application backup that includes all the necessary data? This backup should allow you to restore the entire application, including the database, if you lose your cluster or encounter data loss.</p>
<p>In Kubernetes, think of a Pod as the tiniest unit that you can deploy. It's like a small box that holds one thing, like a web server or a database. So, if your Pod isn't running, your web server or database isn't either.</p>
<p>This means that if the cluster where your Pod runs gets destroyed, all the data in the Pod disappears too. All the nodes (virtual machines that run your application over the network) will also be wiped out.</p>
<p>How can you make a pod stay on one specific node where the data is and never move? And how can you make sure that each pod can be found separately when you're using a load balancer?</p>
<p>One solution is to consider how you deploy your application on Kubernetes. Typically, you create a <strong>deployment</strong> and expose it using a service, specifying the service type as either Cluster type, NodePort, or LoadBalancer.</p>
<p>But not all applications are the same when it comes to state. Some applications, known as stateless applications, don't rely on storing data locally, so losing their state isn't a big issue.</p>
<p>But for applications like databases or caches, maintaining state is crucial because they rely on storage. In Kubernetes, deploying stateful applications like databases using just deployment isn't ideal. You need a solution that ensures your application's data is safely stored and can be recovered in case of failure.</p>
<h3 id="heading-deploymentshttpskubernetesiodocsconceptsworkloadscontrollersdeployment"><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployments</a></h3>
<p>You might be wondering why we can't just use a Kubernetes deployment to deploy Postgres in the Kubernetes cluster? Well, the thing is, many people aren't aware of the difference between a deployment and a stateful set.</p>
<p>Let's imagine you have a pod running in your cluster that you created using a deployment. Then you scaled up to two pods, so you now have Pod A and Pod B.</p>
<p>The problem arises because, by default, pods created as part of the same deployment share the same <strong>persistent volume</strong> (PV) across the cluster. So, when you scaled up, both instances of Postgres would write to the same storage, which could lead to data corruption.</p>
<p>Another issue arises from a networking perspective. Pods A and B don't have a dependable way to communicate with each other over the network. By default, Kubernetes pods don't have their own DNS names. Instead, you rely on <strong>services</strong> to expose ports to other applications in the cluster.</p>
<p>If you take a closer look at pod names, you'll notice that pods are assigned a random hash at the end of their names. Because of this, pods lack a consistent network identity. Every time a pod is destroyed and recreated, it receives a new randomized name. This inconsistency isn't ideal for reliable networking.</p>
<p>Postgres isn't naturally made for <strong>Kubernetes</strong>, and Kubernetes can be tough when handling stateful tasks. To set up a Postgres instance, you've got to know the right Kubernetes setup. You can't just throw it in a pod, because if the pod goes down, so does your data. But, for a quick integration, a pod could work fine.</p>
<p>Deployments aren't ideal either, since you don't want your pod randomly placed on a node. But for testing, deployments are handy if you just need a Postgres instance to run temporarily.</p>
<p>What you really want is a pod that sticks to a particular node where your data resides, and stays put. Plus, you also want your pod to be individually addressable. for this we need what we called a <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/"><strong>statefulSet</strong></a>.</p>
<h3 id="heading-statefulsetshttpskubernetesiodocsconceptsworkloadscontrollersstatefulset"><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/"><strong>StatefulSets</strong></a></h3>
<p>When you update your deployment to become a <strong>StatefulSet</strong>, Kubernetes introduces some improvements for deploying stateful workloads. One major change is how it handles scaling.</p>
<p>If you specify that you want three replicas of your StatefulSet, Kubernetes won't create all three pods at once. Instead, it creates them one by one. Each pod gets its own unique DNS name, starting with the pod's name followed by an ordinal number starting from zero. So, when you scale up, the ordinal number increases for each new pod.</p>
<p>Here's the cool part: if a pod like Pod-0 is destroyed and needs to be remade, it will return with the same name. This means each pod has a specific address, even if it's replaced.</p>
<p>And here's another cool feature: each pod in a StatefulSet gets its own persistent volume (PV). This lets you keep the same storage even if you scale up or down. This brings us to another concept called persistent volumes.</p>
<h3 id="heading-persistent-volumeshttpskubernetesiodocsconceptsstoragepersistent-volumes"><a target="_blank" href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">Persistent Volumes</a></h3>
<p>Let's forget about pods, deployment, and containers for a moment. What exactly is "state"? In simple terms, state is the data that your applications need to work properly.</p>
<p>Now, when we talk about processes, there are two types: stateless and stateful. <strong>Stateless</strong> processes don't rely on any data to work. They just do their thing without needing any specific information. On the other hand, <strong>stateful</strong> processes need data or state to function properly.</p>
<p>Now, where do you store this state? There are two main places: memory and disk. <strong>Memory</strong> allows for quick access to data, which is great for applications like Redis, MongoDB, Postgres, or MySQL. They store their state on memory for quick access. But for persistent, they store it on <strong>disk</strong> on the file system (for more permanent storage).</p>
<p>Why the file system? Because it's the only way to keep the state persistent even when the system reboots. So, when a process dies and gets recreated, it can read its state from the file system.</p>
<p>I like breaking things down because I used to teach tech stuff. Now, let's get into setting up Kubernetes in Azure.</p>
<h2 id="heading-azure-kubernetes-service-aks"><strong>Azure Kubernetes Service (AKS)</strong></h2>
<p>In this section, I'll guide you through setting up a Kubernetes cluster on Azure.</p>
<h3 id="heading-step-1-sign-in-to-your-azure-portal">Step 1: Sign in to your Azure portal</h3>
<p>To begin, you will have to sign into your <a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal">Azure</a> portal. Once logged in, you should see a dashboard similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.39.46.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Azure portal homepage</em></p>
<h3 id="heading-step-2-create-a-resource">Step 2: Create a resource</h3>
<p>Click on "create a resource" to create a resource.</p>
<p>Resources are the various services, components, and assets that you can create and manage within the Azure cloud platform. These resources can include virtual machines, databases, storage accounts, networking components, web applications, and more.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.39.46--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a resource in Azure portal</em></p>
<h3 id="heading-step-3-create-a-new-container">Step 3: Create a new container</h3>
<p>Next, navigate to the "Containers" category from the options available on the left pane. Click on Containers as shown by the arrow in the screenshot.</p>
<p>Again, Kubernetes is a container orchestration platform. It manages and orchestrates the deployment, scaling, and operation of application containers across clusters of machines. Kubernetes provides a framework for automating the deployment, scaling, and management of containerized applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.42.12--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating new container (Kubernetes) in Azure</em></p>
<h3 id="heading-step-4-create-a-new-azure-kubernetes-service-aks"><strong>Step 4: Create a new Azure Kubernetes Service (AKS)</strong></h3>
<p>Select "Azure Kubernetes Service (AKS)" from the list of available container services and click Create. This will take you to the AKS creation page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.42.37--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a new Azure Kubernetes service</em></p>
<h3 id="heading-step-5-create-a-new-resource-group">Step 5: Create a new resource group</h3>
<p>In the "Resource group" section, click on "Create new" to create a new resource group for your Azure Kubernetes Service (AKS) deployment.</p>
<p>In Azure, a "resource group" is a logical container used to group together related Azure resources. It serves as a way to organize and manage these resources collectively, rather than individually.</p>
<p>When you create resources such as virtual machines, databases, storage accounts, or any other Azure service, you typically associate them with a resource group.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.43.09--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating a new resource group in azure portal</em></p>
<p>Let's name the resource group "AZURE-POSTGRES-RG" as shown below. You can name it anything you like. Then click ok.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.43.45.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Inputting name for the resource group</em></p>
<h3 id="heading-step-6-give-your-kubernetes-cluster-a-name">Step 6: Give your Kubernetes cluster a name</h3>
<p>Now let's name the session for configuring the Kubernetes cluster "Kubernetes Cluster Name".</p>
<p>In Azure, a Kubernetes cluster is a managed container orchestration service provided by Azure Kubernetes Service (AKS). It allows you to deploy, manage, and scale containerized applications using Kubernetes without having to manage the underlying infrastructure.</p>
<p>Give it a name like "AZURE-POSTGRES-KC" and and select a region that's close to you. In my case I select (Asia Pacific) East Asia and click next.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.47.34--3-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Naming the Kubernetes cluster name</em></p>
<h3 id="heading-step-7-navigate-to-the-node-pool-page">Step 7: Navigate to the node pool page</h3>
<p>Now it's time to configure the node pool session by clicking on the agentpool.</p>
<p>In Azure, a node pool is a group of virtual machines (VMs) that are provisioned and managed together within an Azure Kubernetes Service (AKS) cluster. Each node pool runs a specific version of Kubernetes and has its own set of configurations, such as VM size, OS image, and node count.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.47.50--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Editing agentpool</em></p>
<p>Set the minimum node count to 1, maximum node count to 2, and the maximum pods per node to 30 to minimise cost. Then click update.</p>
<p>These parameters help control the size and behavior of the node pool in an Azure Kubernetes Service (AKS) cluster:</p>
<ol>
<li><p><strong>Minimum Node Count</strong>: Ensures a minimum number of nodes are always available for consistent performance and availability, even during low-demand periods.</p>
</li>
<li><p><strong>Maximum Node Count</strong>: Sets an upper limit on the number of nodes in the node pool to manage costs and prevent over-provisioning.</p>
</li>
<li><p><strong>Maximum Pods per Node</strong>: Defines the maximum number of pods that can run on each node, optimizing resource utilization and preventing overcrowding.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.48.29--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Updating agentpool details</em></p>
<p>Once you've clicked "Update," you'll be directed to the "Networking" section as shown below. Keep the page as is and proceed by clicking "Next." This will take you to Integration session.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.48.55--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<p>Azure Container Registry (ACR) is a fully managed private Docker registry service provided by Microsoft Azure. It enables developers to store, manage, and deploy Docker container images securely within their Azure environment.</p>
<p>You will need a place to store the Docker image that's pulled.</p>
<p>To begin, select "Create New" to set up a new container registry. This action will bring up a page where you can input the necessary details, as illustrated on the right side of the image below. Enter the details as indicated by the arrows and then click "Okay." Once you're done, proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.49.36--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Naming and editing Azure Container Registry details</em></p>
<h3 id="heading-step-8-enable-container-logs-and-set-up-alerts">Step 8: Enable container logs and set up alerts</h3>
<p>The <strong>Enable Container Logs</strong> option allows you to turn on logging for your containers. Logging records important information about what's happening inside your containers, like errors, warnings, and other events. It's useful for troubleshooting and monitoring your applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.25--2-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Choosing container logs</em></p>
<h3 id="heading-step-9-advanced-section">Step 9: Advanced section</h3>
<p>Keep the Monitoring section unchanged and proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.32.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<h3 id="heading-step-10-tags">Step 10: Tags</h3>
<p>Keep the Tags section unchanged and proceed by clicking "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.50.44.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Navigating to Next Page</em></p>
<h3 id="heading-step-11-click-review-create-to-finalize-the-deployment">Step 11: Click "Review + create" to finalize the deployment</h3>
<p>Once completed, your resource group, Azure Kubernetes Service (AKS), Azure Container Registry, and Kubernetes cluster will be created.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-17.51.39--1-.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Completing Azure Kubernetes Setup</em></p>
<p>The screenshot below shows that the deployment was successful.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-18.01.53.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Successful Deployment</em></p>
<p>You've just successfully created an Azure Kubernetes Service from the Azure portal. Congrats!</p>
<h2 id="heading-how-to-connect-to-your-aks-cluster-using-the-command-line">How to Connect to Your AKS Cluster Using the Command Line</h2>
<p>After successfully creating a new AKS in the Azure portal, the next step is to establish a connection to that cluster.</p>
<p>In this section, I'll guide you through Azure login, configuring kubectl to use the current context, and creating the YAML file for our Postgres container. This file will include StatefulSet, persistent volume, persistent volume claim, config map, and using Azure File for data storage.</p>
<p>I'll also show you how to run a Node.js Express application locally, use Postman to test the endpoints, and receive a response confirming that data was sent to the database successfully.</p>
<h3 id="heading-download-azure-cli-and-kubectl">Download Azure CLI and kubectl</h3>
<p>To start, you'll need to download the Azure CLI and kubectl.</p>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli"><strong>Azure CLI</strong></a> <strong>(Command-Line Interface)</strong>: a command-line tool provided by Microsoft for managing Azure resources. It allows users to interact with Azure services and resources directly from the command line, making it easy to automate tasks, create scripts, and manage Azure resources programmatically.</p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/tasks/tools/"><strong>kubectl</strong></a>: a command-line tool for managing Kubernetes clusters, used to deploy, scale, and manage containerized applications. It allows users to perform operations like deploying applications, managing pods, services, and deployments, inspecting cluster resources, scaling applications, and debugging issues, simplifying management of containerized workloads in a Kubernetes environment.</p>
</li>
</ul>
<p>I'm using the warp terminal. <a target="_blank" href="https://www.warp.dev/">Warp</a> is the terminal reimagined with AI and collaborative tools for better productivity. You can run the command using PowerShell on Windows or Terminal on Mac. I'm using a MacBook.</p>
<h3 id="heading-verify-if-the-azure-cli-is-installed-by-typing-the-command-az-version">Verify if the Azure CLI is installed by typing the command <code>az --version</code></h3>
<p>Once the download finishes, verify whether Azure CLI is installed on your computer by running the command <code>az --version</code>. If the installation is successful, you should see an output similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.18.48.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying Azure CLI Installation</em></p>
<h3 id="heading-verify-if-kubectl-is-installed">Verify if kubectl is installed</h3>
<p>To check if kubectl is installed, just type <code>kubectl version</code> in the command line.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.31.01.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying Kubectl Installation</em></p>
<h3 id="heading-login-to-your-azure-account">Login to your Azure account</h3>
<p>Enter <code>az login</code> in the command line. This will open your browser and prompt you to sign in to your Azure account.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-21.47.47.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Logging into Azure</em></p>
<p>After signing in, it shows details about your Azure subscription, including the subscription name, ID, and user information.</p>
<h3 id="heading-select-an-azure-subscription">Select an Azure subscription</h3>
<p>Azure subscriptions are logical containers used to provision resources in Azure. You'll need to locate the subscription ID that you plan to use in this module. Use the command to list your Azure subscriptions:</p>
<pre><code class="lang-bash">az account list --output table
</code></pre>
<p>Use the following command to ensure you're using an Azure subscription that allows you to create resources for the purpose of this module, substituting your subscription ID (SubscriptionId):</p>
<pre><code class="lang-bash">az account <span class="hljs-built_in">set</span> --subscription <span class="hljs-string">"Name of the subscription"</span>
</code></pre>
<h3 id="heading-configure-kubectl-to-connect-to-your-azure-kubernetes">Configure kubectl to connect to your Azure Kubernetes</h3>
<p>Replace <code>Your_Azure_Resource_groups_name</code> in the code below with the name you chose when creating a resource group. Also, replace <code>your_azure_kubernetes_service_name</code> with the name of your Kubernetes cluster. Then, execute the following command:</p>
<pre><code class="lang-bash">az aks get-credentials --resource-group [Your_Azure_Resource_groups_name] --name [your_azure_kubernetes_service_name]
</code></pre>
<p>The output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.07.20.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Merging kubectl with Azure Kubernetes Service</em></p>
<h3 id="heading-verify-if-kubectl-has-been-merged-successfully">Verify if kubectl has been merged successfully</h3>
<p>Run the following command <code>kubectl get nodes</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.09.33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Verifying if merged is successful</em></p>
<p>When you run this command, Kubernetes communicates with the cluster's control plane to fetch a list of all the nodes that are part of the cluster you created. As you can see, this is the node that was running in the Kubernetes cluster we created inside Azure.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-18.04.07.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Virtual Node running in AKS cluster</em></p>
<h3 id="heading-run-the-command-kubectl-get-pods">Run the command <code>kubectl get pods</code></h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.18.19.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying Pod Information</em></p>
<p>When you run the command <code>kubectl get pods</code>, Kubernetes attempts to retrieve information about all pods within the default namespace of your cluster. But in this case, the output indicates that there are no resources (pods) found within the default namespace, implying that no pods currently exist in that namespace.</p>
<p>A <strong>namespace</strong> in Kubernetes is a virtual cluster environment within which resources like pods, services, and deployments are organized and isolated. It's a way to divide cluster resources between multiple users, teams, or projects. Namespaces provide a scope for names and make it easier to manage and control access to resources.</p>
<p>By default, Kubernetes starts with a "default" namespace, but you can create additional namespaces to organize and manage resources more effectively. Namespaces help prevent naming conflicts and provide a logical separation of resources, allowing different teams or projects to work independently within the same Kubernetes cluster.</p>
<h3 id="heading-create-a-namespace">Create a namespace</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.24.40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating Namespace</em></p>
<p>When you run the command <code>kubectl create namespace database</code>, Kubernetes creates a new namespace named "database." The output "namespace/database created" confirms that the namespace has been successfully created.</p>
<p>You can now use this namespace to organize and manage resources related to databases within the Kubernetes cluster.</p>
<h3 id="heading-confirm-the-namespace">Confirm the namespace</h3>
<p>The command <code>kubectl get namespace</code> lists all namespaces in the Kubernetes cluster including the database namespace we just created, showing their names, status (active), and age.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.26.22.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Confirming namespace</em></p>
<h3 id="heading-get-pod-information-in-database-namespace">Get pod information in database namespace</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-05-at-22.35.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying Pod Information related to database namespace</em></p>
<p>This command, <code>kubectl get pods -n database</code>, attempts to fetch information about pods specifically within the "database" namespace. But the output <code>No resources found in database namespace</code> indicates that there are currently no pods deployed in the "database" namespace.</p>
<h2 id="heading-how-to-create-resources-with-yaml">How to Create Resources with YAML</h2>
<p>Let's explore creating resources with YAML to provision our PostgreSQL database running in an Azure Kubernetes cluster. But first, what exactly is YAML?</p>
<p>Kubernetes <a target="_blank" href="https://www.redhat.com/en/topics/automation/what-is-yaml"><strong>YAML</strong></a> is a configuration file written in YAML (YAML Ain't Markup Language). They define how Kubernetes resources like pods, deployments, and services should be set up within a cluster. These files are easy to read and specify details like resource names, types, specifications, labels, and annotations. They're crucial for deploying applications and infrastructure on Kubernetes clusters.</p>
<p>YAML is what you will use to create Kubernetes resources that will run Postgres.</p>
<p>First, you need to <a target="_blank" href="https://github.com/ayowilfred95/Azure-k8s-postgres.git">clone this GitHub repository</a>. Inside, you'll find a Node.js Express application and a YAML file. The Node.js app allows users to register with their email, password, and full name, and also enables them to log in by verifying their details in the database. If their details are found, it displays a success message.</p>
<h3 id="heading-clone-the-repository">Clone the repository</h3>
<p>Create a new folder on your computer and then clone this <a target="_blank" href="https://github.com/ayowilfred95/Azure-k8s-postgres.git">repository</a> into it.</p>
<p>Open your terminal or PowerShell, go to the folder you want, and use the command below to clone the repository into your computer in that location.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/ayowilfred95/Azure-k8s-postgres.git
</code></pre>
<h3 id="heading-open-the-cloned-repository-in-any-text-editor">Open the cloned repository in any text editor</h3>
<p>I'm using Visual Studio Code, but feel free to use any text editor you prefer. Here's the structure of the project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-04.15.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Project folder structure</em></p>
<h3 id="heading-install-project-dependencies">Install project dependencies</h3>
<p>Open the terminal in VS Code and go to the main directory of the project. Next, execute the command <code>npm install</code> to install all the required packages and dependencies for the project:</p>
<pre><code class="lang-bash">npm install
</code></pre>
<p>Since the backend application is a Node.js Express app, you use npm to install dependencies (similar to how we use <code>maven clean install</code> in Java).</p>
<p>After the dependencies are installed, open the file named "postgres.yaml". It holds all the YAML configurations required to set up your PostgreSQL database that will run in the Kubernetes cluster.</p>
<h2 id="heading-yaml-configuration">YAML Configuration</h2>
<p>In the postgres.yaml file, there are five configurations separated by ---. It's important to use this "---" symbol when declaring different types of Kubernetes resources. If you forget to do this, you'll encounter an error.</p>
<h3 id="heading-storageclass">StorageClass</h3>
<p>The first one is the <code>StorageClass</code>. This YAML configuration defines a StorageClass in Kubernetes for managing storage resources.</p>
<pre><code class="lang-bash">kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azuredisk-premium-retain
provisioner: kubernetes.io/azure-disk
reclaimPolicy: Retain   <span class="hljs-comment"># Retain or Delete</span>
volumeBindingMode: WaitForFirstConsumer   <span class="hljs-comment"># WaitForFirstConsumer or Immediate</span>
allowVolumeExpansion: <span class="hljs-literal">true</span>    <span class="hljs-comment"># true or false</span>
parameters:
  storageaccounttype: Premium_LRS   <span class="hljs-comment"># Premium or Standard</span>
  kind: Managed
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>kind: StorageClass</code>: Indicates the type of Kubernetes resource being defined, which is a <code>StorageClass</code>. A <code>StorageClass</code> defines the class of storage offered by a cluster.</p>
</li>
<li><p><code>apiVersion: storage.k8s.io/v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>metadata: name: azuredisk-premium-retain</code>: Provides metadata for the <code>StorageClass</code>, including its name, which in this case is "azuredisk-premium-retain".</p>
</li>
<li><p><code>provisioner: kubernetes.io/azure-disk</code>: Specifies the provisioner responsible for provisioning storage. In this case, it's "kubernetes.io/azure-disk", indicating that Azure Disk will be used as the storage provisioner.</p>
</li>
<li><p><code>reclaimPolicy: Retain</code>: Defines the reclaim policy for the storage resources. It specifies what action should be taken when the associated persistent volume is released. Here, it's set to "Retain", meaning the volume is retained even after it's no longer used by a pod.</p>
</li>
<li><p><code>volumeBindingMode: WaitForFirstConsumer</code>: Specifies the volume binding mode, which determines when volume binding should occur. In this case, it's set to "WaitForFirstConsumer", meaning the volume will be bound when the first pod using it is created.</p>
</li>
<li><p><code>allowVolumeExpansion: true</code>: Indicates whether volume expansion is allowed. Setting it to "true" means that the size of the volume can be increased if needed.</p>
</li>
<li><p><code>parameters</code>: Contains additional parameters specific to the provisioner. Here, it specifies the storage account type as "Premium_LRS" and the kind of storage as "Managed".</p>
</li>
</ul>
<p>Overall, this configuration sets up a <code>StorageClass</code> named "azuredisk-premium-retain" using Azure Disk as the provisioner, with specific policies and parameters tailored for Azure storage.</p>
<h3 id="heading-persistentvolumeclaim">PersistentVolumeClaim</h3>
<p>The second configuration in the postgres.yaml file is the <strong>persistent volume claim</strong>.</p>
<p>This YAML configuration defines a <code>PersistentVolumeClaim</code> (PVC) in Kubernetes, which is used to request storage resources.</p>
<pre><code class="lang-bash">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: azure-managed-disk-pvc
spec:
  accessModes:
  - ReadWriteOnce   <span class="hljs-comment"># ReadWriteOnce, ReadOnlyMany or ReadWriteMany</span>
  storageClassName: azuredisk-premium-retain
  resources:
    requests:
      storage: 4Gi
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: PersistentVolumeClaim</code>: Indicates the type of Kubernetes resource being defined, which is a PersistentVolumeClaim. A PVC is used by pods to request storage resources.</p>
</li>
<li><p><code>metadata: name: azure-managed-disk-pvc</code>: Provides metadata for the PersistentVolumeClaim, including its name, which is "azure-managed-disk-pvc".</p>
</li>
<li><p><code>spec</code>: Describes the desired state of the PersistentVolumeClaim.</p>
</li>
<li><p><code>accessModes: - ReadWriteOnce</code>: Specifies the access mode for the volume. Here, it's set to "ReadWriteOnce", meaning the volume can be mounted as read-write by a single node at a time.</p>
</li>
<li><p><code>storageClassName: azuredisk-premium-retain</code>: Specifies the <code>StorageClass</code> to use for provisioning the volume. This PVC will use the <code>StorageClass</code> named "azuredisk-premium-retain" defined previously.</p>
</li>
<li><p><code>resources: requests: storage: 4Gi</code>: Specifies the desired storage capacity for the volume. Here, it requests 4 gigabytes (Gi) of storage.</p>
</li>
</ul>
<p>Overall, this configuration sets up a <code>PersistentVolumeClaim</code> named "azure-managed-disk-pvc" requesting storage resources with specific access modes, storage class, and storage capacity.</p>
<h3 id="heading-configmap">ConfigMap</h3>
<p>The third configuration in the postgres.yaml file is the <strong>config map</strong>. This YAML configuration defines a ConfigMap in Kubernetes, which is used to store configuration data in key-value pairs.</p>
<pre><code class="lang-bash">apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-config
  labels:
    app: postgres
data:
  POSTGRES_DB: freecodecamp
  POSTGRES_USER: freecodecamp1
  POSTGRES_PASSWORD: freecodecamp@
  PGDATA: /var/lib/postgresql/data/pgdata
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: ConfigMap</code>: Indicates the type of Kubernetes resource being defined, which is a <code>ConfigMap</code>. A <code>ConfigMap</code> is used to store non-confidential data in key-value pairs.</p>
</li>
<li><p><code>metadata: name: postgres-config</code>: Provides metadata for the <code>ConfigMap</code>, including its name, which is "postgres-config".</p>
</li>
<li><p><code>labels: app: postgres</code>: Labels are key-value pairs used to organize and select resources. Here, a label "app" with the value "postgres" is applied to the <code>ConfigMap</code>.</p>
</li>
<li><p><code>data</code>: Contains the key-value pairs of configuration data.</p>
</li>
<li><p><code>POSTGRES_DB: pisonitsha</code>: Specifies the name of the PostgreSQL database as "pisonitsha".</p>
</li>
<li><p><code>POSTGRES_USER: pisonitsha1</code>: Specifies the username for accessing the PostgreSQL database as "pisonitsha1".</p>
</li>
<li><p><code>POSTGRES_PASSWORD: pisonitsha@</code>: Specifies the password for accessing the PostgreSQL database as "pisonitsha@".</p>
</li>
<li><p><code>PGDATA: /var/lib/postgresql/data/pgdata</code>: Specifies the location of PostgreSQL data directory as "/var/lib/postgresql/data/pgdata".</p>
</li>
</ul>
<p>Overall, this configuration sets up a ConfigMap named "postgres-config" containing key-value pairs of configuration data, such as database name, username, password, and data directory location, which can be used by other Kubernetes resources.</p>
<p><strong>Note:</strong> It's recommended to avoid hardcoding secret variables such as <code>POSTGRES_DB</code>, <code>POSTGRES_PASSWORD</code>,<code>PGDATA</code> and instead store them in secret files, for the sake of simplicity in this tutorial, we'll keep them hardcoded.</p>
<h3 id="heading-statefulset">StatefulSet</h3>
<p>The fourth configuration is the <strong>stateful set</strong>.This YAML configuration defines a <code>StatefulSet</code> in Kubernetes, which is used to manage stateful applications like databases.</p>
<pre><code class="lang-bash">apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  selector:
    matchLabels:
      app: postgres
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:10.4
          imagePullPolicy: <span class="hljs-string">"IfNotPresent"</span>
          ports:
          - containerPort: 5432
          envFrom:
          - configMapRef:
              name: postgres-config
          volumeMounts:
          - name: azure-managed-disk-pvc
            mountPath: /var/lib/postgresql/data
      volumes:
      - name: azure-managed-disk-pvc
        persistentVolumeClaim:
          claimName: azure-managed-disk-pvc
    ```

Let<span class="hljs-string">'s break down what each part means:

* `apiVersion: apps/v1`: Specifies the Kubernetes API version being used for this resource.
* `kind: StatefulSet`: Indicates the type of Kubernetes resource being defined, which is a `StatefulSet`. `StatefulSets` are used to manage stateful applications by providing unique **identities** and stable **network** identities to each pod.
* `metadata: name: postgres`: Provides metadata for the `StatefulSet`, including its name, which is "postgres".
* `spec`: Describes the desired state of the `StatefulSet`.
* `serviceName: postgres`: Specifies the name of the Kubernetes service that will be used to access the `StatefulSet` pods.
* `selector: matchLabels: app: postgres`: Selects the pods controlled by this `StatefulSet` based on the label "app: postgres".
* `replicas: 1`: Specifies the desired number of replicas (instances) of the StatefulSet, which is 1 in this case.
* `template`: Defines the pod template used to create pods managed by the `StatefulSet`.
* `metadata: labels: app: postgres`: Labels applied to the pods created from this template.
* `spec`: Describes the specification of the containers within the pod.
* `containers`: Specifies the containers running in the pod.
* `name: postgres`: Defines the name of the container as "postgres".
* `image: postgres:10.4`: Specifies the Docker image used for the container, which is "postgres:10.4".
* `imagePullPolicy: "IfNotPresent"`: Specifies the policy for pulling the container image, which is "IfNotPresent", meaning it will only pull the image if it'</span>s not already present on the node.
* `ports: containerPort: 5432`: Specifies the port that the PostgreSQL service inside the container is listening on.
* `envFrom: configMapRef: name: postgres-config`: Injects environment variables from a ConfigMap named <span class="hljs-string">"**postgres-config**"</span> that you defined earlier.
* `volumeMounts: name: azure-managed-disk-pvc mountPath: /var/lib/postgresql/data`: Mounts a persistent volume claim named <span class="hljs-string">"azure-managed-disk-pvc"</span> to the container at the specified path.
* `volumes: name: azure-managed-disk-pvc persistentVolumeClaim: claimName: azure-managed-disk-pvc`: Defines the persistent volume claim named <span class="hljs-string">"azure-managed-disk-pvc"</span> to be used by the pod.

Overall, this configuration sets up a StatefulSet named <span class="hljs-string">"postgres"</span> with one replica, running a PostgreSQL container with specific settings and mounted persistent storage.

<span class="hljs-comment">### Service</span>

The fifth configuration is the **service**. This YAML configuration defines a **Service** <span class="hljs-keyword">in</span> Kubernetes, <span class="hljs-built_in">which</span> is used to expose the `StatefulSet` we declared earlier as a network service.

```bash
apiVersion: v1
kind: Service
metadata:
  name: postgres
  labels:
    app: postgres
spec:
  <span class="hljs-built_in">type</span>: LoadBalancer
  selector:
    app: postgres
  ports:
    - protocol: TCP
      name: https
      port: 5432
      targetPort: 5432
</code></pre>
<p>Let's break down what each part means:</p>
<ul>
<li><p><code>apiVersion: v1</code>: Specifies the Kubernetes API version being used for this resource.</p>
</li>
<li><p><code>kind: Service</code>: Indicates the type of Kubernetes resource being defined, which is a Service. <strong>Services</strong> allow pods to be accessed by other pods or external users.</p>
</li>
<li><p><code>metadata: name: postgres</code>: Provides metadata for the Service, including its name, which is "postgres".</p>
</li>
<li><p><code>labels: app: postgres</code>: Labels are key-value pairs used to organize and select resources. Here, a label "app" with the value "postgres" is applied to the Service.</p>
</li>
<li><p><code>spec</code>: Describes the desired state of the Service.</p>
</li>
<li><p><code>type: LoadBalancer</code>: Specifies the type of Service, which is "LoadBalancer". This type allows the <strong>Service</strong> to be exposed externally with a cloud provider's load balancer.</p>
</li>
<li><p><code>selector: app: postgres</code>: Selects the pods controlled by the Service based on the label "app: postgres".</p>
</li>
<li><p><code>ports</code>: Specifies the ports that the Service will listen on.</p>
</li>
<li><p><code>protocol: TCP</code>: Specifies the protocol used for the port, which is TCP.</p>
</li>
<li><p><code>name:https</code> : Specifies a name for the port, which is "https".</p>
</li>
<li><p><code>port: 5432</code>: Specifies the port number on which the Service will listen, which is 5432.</p>
</li>
<li><p><code>targetPort: 5432</code>: Specifies the target port on the pods to which traffic will be forwarded, which is also 5432. This means that traffic received on port 5432 of the Service will be forwarded to port 5432 on the pods.</p>
</li>
</ul>
<p>Overall, this configuration sets up a Service named "postgres" with a LoadBalancer type, forwarding traffic on port 5432 to pods labeled with "app: postgres".</p>
<h2 id="heading-how-to-deploy-yaml-resource-to-azure-kubernetes-service-aks">How to Deploy YAML Resource to Azure Kubernetes Service (AKS)</h2>
<p>You've previously connected "kubectl" with the Azure Kubernetes Service (AKS) you set up. Let's double-check it.</p>
<p>In your VS Code terminal, rerun the command <code>kubectl get nodes</code>. You'll see an output like this, though your node's value will be different.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-05-06-at-05.49.43.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Displaying node information running in Azure Kubernetes cluster</em></p>
<p>Next, verify the namespace you previously created by executing the command: <code>kubectl get namespace database</code>. Your output should resemble this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-05.49.12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Retrieving Namespace Information</em></p>
<h3 id="heading-deploy-the-yaml-resource">Deploy the YAML resource</h3>
<p>Once you've confirmed everything is set, you can deploy the YAML resource. This will establish your PostgreSQL database in the Azure Kubernetes cluster you've configured.</p>
<p>Run the below command in the main directory where the configuration file is located. Currently, I'm in the project's root directory (azure-k8s-postgres). To deploy the database, just execute this command below:</p>
<pre><code class="lang-bash">kubectl apply -n database -f postgres.yaml
</code></pre>
<p>Your output should look like this. This output confirms that all these components have been successfully created in Kubernetes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-05.57.52.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Applying Configuration to Namespace</em></p>
<p>Execute the command below to verify that the pod is running:</p>
<pre><code class="lang-bash">kubectl get pods -n database
</code></pre>
<p>Your output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.01.33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Fetching Pods in Namespace</em></p>
<p>This output confirms that a pod name "postgres-0" is running in your Azure Kubernetes Cluster. But it was not the only pod you created. As I said earlier, to connect to a pod, you need what is called service. And you have declared a service resource in our configuration file which has also been deployed into your Kubernetes.</p>
<p>To get the status of the service, run this command:</p>
<pre><code class="lang-bash">kubectl get services -n database
</code></pre>
<p>Your output should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.07.12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Retrieving Services in Namespace</em></p>
<p>This output displays the services in the "database" namespace, including a service named "postgres" with the type "LoadBalancer," its internal cluster IP, external IP, and port mappings. You'll utilize the external IP along with the Postgres port "5432" to connect your database with the Node.js application. Note that your external IP will differ from mine.</p>
<h2 id="heading-nodejs-application">Node.js Application</h2>
<p>In this section, I'll guide you through setting up your Node.js app to connect to a PostgreSQL database in your Azure Kubernetes Service.</p>
<p>We'll cover sending data into the database and retrieving it using Postman. Also, I'll demonstrate how to check if the data remains in the database even if the pod running PostgreSQL in the cluster is deleted.</p>
<h3 id="heading-configure-your-nodejs-application">Configure your Node.js application</h3>
<p>Go to the database folder and open the database.js file. Replace the host with your EXTERNAL-IP obtained from the service, and leave the rest unchanged since you've already defined those variables in your config map.</p>
<p>Your database.js file should resemble the CodeSnap below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/code.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>CodeSnap of database.js Configuration</em></p>
<h3 id="heading-run-your-nodejs-application">Run your Node.js application</h3>
<p>In your VS Code terminal, execute this command to start the Node.js application locally:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Your output should look like this if the connection is established successfully.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.27.25.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Server Listening on Port 4000</em></p>
<p>If your output looks the same as mine, it indicates that you've successfully connected your Node.js application to the PostgreSQL database running in your Azure Kubernetes cluster. Congratulations! 🎉</p>
<h3 id="heading-test-the-application">Test the application</h3>
<p>Testing is a fundamental principle in DevOps operations. It helps us understand the state of the application we've built before releasing it to users. Any application that doesn't pass the testing stage will not be deployed. This is a rule in DevOps.</p>
<p>For this tutorial, you'll be using Postman. You can download Postman <a target="_blank" href="https://www.postman.com/downloads/">here</a>. Postman enables you to test API endpoints by receiving status responses.</p>
<p>Check out this <a target="_blank" href="https://qalified.com/blog/postman-for-api-testing/">post</a> on how to use Postman to test APIs. If you want to learn more, <a target="_blank" href="https://www.freecodecamp.org/news/learn-how-to-use-postman-to-test-apis/">here's a full course</a> on the subject.</p>
<h3 id="heading-open-your-postman-application">Open your Postman application</h3>
<p>To begin using Postman, start by creating a new API request in your preferred workspace. Choose POST. POST requests add new data to the database or server. Then, paste the endpoint URL (localhost:4000/api/v1/admin/register) for your Postman test.</p>
<p>The below screenshot illustrates how you will create a POST request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.32.32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman URL Endpoint Configuration</em></p>
<p>In the body, paste the JSON data shown below inside it as shown below:</p>
<pre><code class="lang-bash">{   
    <span class="hljs-string">"fullName"</span>:<span class="hljs-string">"Azure postgres freecodecamp"</span>,
    <span class="hljs-string">"email"</span>:<span class="hljs-string">"freecodecamp@gmail.com"</span>,
    <span class="hljs-string">"password"</span>:<span class="hljs-string">"freecodecamp"</span>
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.34.58-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman Request Body</em></p>
<p>Once you've set up the request, just click the "Send" button to send it. Postman will then show you status codes, and the response payload as shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-06.56.39.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman API Response</em></p>
<h3 id="heading-confirm-the-data">Confirm the data</h3>
<p>To confirm that the data you sent into the database exists, make a GET request to this endpoint URL: localhost:4000/api/v1/admin/freecodecamp@gmail.com</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.45.41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman GET Request URL Endpoint</em></p>
<p>When you click send, Postman will then show you status codes and the response payload as shown below. Notice that we didn't put anything in the body because this is a GET request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-15.48.29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Postman GET Request by Email Retrieval Response</em></p>
<h3 id="heading-delete-the-pod-to-confirm-data-persistence">Delete the pod to confirm data persistence</h3>
<p>We chose to create our PostgreSQL database using a <code>StatefulSet</code> to ensure that data persists even if the pod is destroyed. Let's test this by deleting the pod and checking if the data remains intact.</p>
<p>In your VS Code terminal, execute the command: <code>kubectl delete pod -n database postgres-0</code>.</p>
<p>This command deletes a pod named "postgres-0" in the "database" namespace from your Kubernetes cluster. Your output should look like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-07.09.41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Deleting Pod in Namespace:</em></p>
<h3 id="heading-pod-recreation">Pod recreation</h3>
<p>Kubernetes has a built-in feature called replication controllers or replica sets that ensure a specified number of pod replicas are running at any given time. If a pod is deleted, Kubernetes will automatically recreate it to maintain the desired number of replicas, ensuring high availability</p>
<p>If you run <code>kubectl get pods -n database</code>, you'll notice that Kubernetes has created a new pod with the same name, "postgres-0", to replace the one that was deleted. This ensures that the application remains available and continues to function as expected.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-07.10.04.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Pod Recreated back in Namespace</em></p>
<h3 id="heading-data-persistence">Data persistence</h3>
<p>Navigate back to Postman and make a GET request to the endpoint URL localhost:4000/api/v1/admin/freecodecamp@gmail.com.</p>
<p>You should get the same response as before. So under the hood, when we delete the pod, the storage disk was not deleted. The storage disk is inside the Azure disk. How do we know that? If you run this command:</p>
<pre><code class="lang-bash">kubectl get pvc -n database
</code></pre>
<p>you should get this output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Screenshot-2024-05-06-at-16.04.48-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Persistennce Volume Claim details in namespace</em></p>
<p>This shows details about a storage called "azure-managed-disk-pvc" in your Kubernetes. It's currently in use and has 4 gigabytes of space available. It's set up to be read and written to by one system at a time. This storage is provided by a service called "azuredisk-premium-retain" that we configured earlier.</p>
<h3 id="heading-clean-up-resources">Clean up resources</h3>
<p>In this tutorial, you created Azure resources in a resource group. If you won't need these resources later, delete the resource group from the Azure portal or run the following command in your terminal:</p>
<pre><code class="lang-bash">az group delete --name AZURE-POSTGRES-RG --yes
</code></pre>
<p>This command might take a minute to run.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've gone on quite a journey here! You've learned how to deploy a Postgres container in Azure Kubernetes Service (AKS) and integrate it with a Node.js application.</p>
<p>In this tutorial, I guided you through the process of configuring Kubernetes using Azure Kubernetes Service (AKS). You learned to customize YAML files utilizing StatefulSet, Persistent Volume, and Services to deploy a PostgreSQL database on Azure Kubernetes. You also acquired PostgreSQL database credentials running within AKS to establish connectivity with a Node.js application. I then provided detailed instructions on connecting your Node.js Express app to the Postgres container within the AKS cluster.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Relationship Based Access Control (ReBAC) ]]>
                </title>
                <description>
                    <![CDATA[ By Imran In today's digital age, managing who can access what resources is more critical than ever. That's where ReBAC comes in. It's a fresh take on authorization, focusing on the relationships between different entities rather than just assigning s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/implement-relationship-based-access-control/</link>
                <guid isPermaLink="false">66d45f31246e57ac83a2c76f</guid>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 08 Mar 2024 14:08:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/RELATIONSHIP-BASED-ACCESS-CONTROL.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Imran</p>
<p>In today's digital age, managing who can access what resources is more critical than ever. That's where ReBAC comes in. It's a fresh take on authorization, focusing on the relationships between different entities rather than just assigning static roles or attributes.</p>
<p>Traditional access control methods, like Role-Based Access Control (RBAC), assign specific roles to users. While this works in many cases, it can become difficult, especially in dynamic environments where roles and permissions need to adapt quickly. On the other hand, Attribute-Based Access Control (ABAC) offers flexibility based on user attributes, but it can get complex to manage.</p>
<p>Now, ReBAC is all about understanding the intricate web of relationships between entities. Whether it's within an organization, a social media platform, or a project management tool, ReBAC ensures that access control remains dynamic and context-aware.</p>
<p>By the end of this tutorial, you'll have a clear understanding of ReBAC and be able to model a ReBAC scenario.</p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><strong>ReBAC Principles:</strong> Understand how ReBAC uses relationships between entities for access control, differing from traditional models.</li>
<li><strong>Policy Visualization:</strong> Learn about representing policies as graphs for clearer management.</li>
<li><strong>Real-World Examples:</strong> Explore ReBAC's application in scenarios like social media platforms and project management tools.</li>
<li><strong>Benefits of ReBAC:</strong> Discover the advantages like granular control and dynamic policy adaptation.</li>
<li><strong>Permission Models:</strong> Get familiar with ReBAC's common models such as Ownership and Hierarchical Models.</li>
<li><strong>Permify Implementation:</strong> Step-by-step guide to implement ReBAC in Permify, including entity definition, relationship establishment, and permissions setup.</li>
</ul>
<h2 id="heading-what-is-relationship-based-access-control-rebac">What is Relationship-Based Access Control (ReBAC)?</h2>
<p>Traditional access control methods, like Role-Based Access Control (RBAC), assign specific roles to users, like giving someone a badge that says "manager" or "employee". But what if the roles aren't so clear-cut, and relationships between people and resources matter more?</p>
<p>That's where Relationship-Based Access Control (ReBAC) steps in. Instead of relying solely on predefined roles or attributes, ReBAC considers the intricate web of connections between users, resources, and other entities. It's like saying, "You can access this because you're connected to it in this specific way", rather than just based on a generic label.</p>
<p>But how does ReBAC actually do this? ReBAC examines the relationships between entities, such as users and resources, and uses these connections to determine access.</p>
<p>Let's break it down further. In our everyday lives, we have relationships that matter. Think about social media – you can see certain posts because you're friends with someone or because someone you follow liked it. ReBAC takes this idea and applies it to access control in systems.</p>
<h2 id="heading-policy-as-a-graph">Policy as a Graph</h2>
<p>At the core of ReBAC lies the concept of "Policy as a Graph". This idea shows the importance of visualizing access policies through relationships.</p>
<p>Imagine that you have a detailed map of a bustling city. It doesn't just show buildings but also the connections between them – the roads, bridges, and pathways that link everything together.</p>
<p>Now, picture this map as a representation of your organization. Instead of buildings, it represents team members, departments, and their roles. The connections between them symbolize the relationships that dictate access.</p>
<p>This is what we mean by "Policy as a Graph" in ReBAC.</p>
<p>In simpler terms, access policies are like interconnected dots on a graph. Each dot represents an entity, and the lines between them signify the relationships influencing authorization. It's a visual representation that helps us understand the complex web of connections that govern access.</p>
<h2 id="heading-how-is-rebac-different-from-other-control-models">How is ReBAC Different from Other Control Models?</h2>
<p>Now, let's explore how ReBAC sets itself apart from other access control models, such as Role-Based Access Control (RBAC).</p>
<p>Unlike traditional models, ReBAC doesn't rely solely on rigid roles or attributes. Instead, it works on deriving permissions from existing relationships. Here's how it stands out:</p>
<ul>
<li><strong>Role Derivation:</strong>ReBAC allows the creation of authorization policies based on pre-existing relationships. This means that assigning a user a certain role in one context might automatically extend that role to related entities, saving the need for manual assignment.</li>
<li><strong>Resource Roles:</strong>Unlike global roles in traditional models, ReBAC introduces the concept of resource-specific roles (for example: Folder#Owner). These roles are exclusive to the context of a particular resource, ensuring that permissions are relevant and tailored to that specific entity.</li>
</ul>
<h2 id="heading-real-world-examples">Real-World Examples</h2>
<p>To better understand how Relationship-Based Access Control (ReBAC) functions in the real world, let's explore two scenarios that mimic everyday complexities.</p>
<p>These examples will help illustrate how ReBAC excels in managing intricate access dynamics.</p>
<h3 id="heading-instagram-like-social-platform">Instagram-like Social Platform</h3>
<p>Consider an Instagram-inspired platform where users hold individual accounts. Each account consists of user-generated content, namely pictures (Pic 1 and Pic 2), chat interactions with different users, and project collaboration.</p>
<p>The user account possesses a list of blocked users who are restricted from viewing pictures. Here's a detailed breakdown of the entities and permissions:</p>
<h4 id="heading-1-account-entities">1. Account Entities</h4>
<ul>
<li><strong>User Account:</strong> Represents individual user accounts on the platform.</li>
<li><strong>Pictures (Pic 1 and Pic 2):</strong> Depict user-generated visual content.</li>
<li><strong>Chats:</strong> Captures interaction histories with different users.</li>
<li><strong>Blocked Users List:</strong> Maintains a list of users who are blocked from viewing pictures.</li>
</ul>
<h4 id="heading-2-permissions-dynamics">2. Permissions Dynamics</h4>
<h5 id="heading-account-access-permissions">Account Access Permissions:</h5>
<ul>
<li>"Account#Owner" grants ownership, allowing the user account holder to manage all aspects.</li>
<li>"Account#Viewer" enables others to view the user's account.</li>
</ul>
<h5 id="heading-picture-management-permissions">Picture Management Permissions:</h5>
<ul>
<li>"Picture#Owner" designates ownership at the picture level, allowing the user to edit, delete, and upload pictures.</li>
<li>"Picture#Viewer" permits normal viewers to only view pictures.</li>
<li>"BlockedUser#CannotView" ensures that blocked users cannot view pictures.</li>
</ul>
<h5 id="heading-chat-interaction-permissions">Chat Interaction Permissions:</h5>
<ul>
<li>"Chat#Participant" allows users to participate in chat interactions.</li>
<li>"Chat#BlockedUser" restricts certain users from participating in chats.</li>
</ul>
<h5 id="heading-account-editing-permissions">Account Editing Permissions:</h5>
<ul>
<li>"Account#Edit" grants the ability to update account details and preferences.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Instagram.png" alt="Instagram.png" width="600" height="400" loading="lazy">
<em>Instagram-like Social Platform Entities</em></p>
<p>In this scenario, the "#" symbol represents the relationship between entities when defining permissions. For example, "Account#Owner" signifies ownership of the user account, allowing the account holder to manage all aspects of their account.</p>
<h3 id="heading-project-management-tool">Project Management Tool</h3>
<p>Imagine a project management tool where teams collaborate on various projects. Entities like "Teams", "Projects", and "Tasks" play central roles, showcasing ReBAC's adaptability:</p>
<h4 id="heading-1-team-entities">1. Team Entities:</h4>
<ul>
<li><strong>Teams:</strong> Represent collaborative groups within the project management tool.</li>
<li><strong>Projects:</strong> Encompass various ongoing initiatives.</li>
<li><strong>Tasks:</strong> Break down project activities into manageable tasks.</li>
</ul>
<h4 id="heading-2-permissions-dynamics-1">2. Permissions Dynamics:</h4>
<h5 id="heading-team-leadership-permissions">Team Leadership Permissions:</h5>
<ul>
<li>"Team#Lead" designates team leadership, allowing leaders to manage team-related activities.</li>
</ul>
<h5 id="heading-project-ownership-permissions">Project Ownership Permissions:</h5>
<ul>
<li>"Project#Owner" signifies ownership at the project level, granting comprehensive control over project-related actions.</li>
</ul>
<p><strong>Task Assignment Permissions:</strong></p>
<ul>
<li>"Task#Assignee" designates individuals responsible for specific tasks.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/project.png" alt="project.png" width="600" height="400" loading="lazy">
<em>Project Management Tool Entities</em></p>
<p>These real-world scenarios demonstrate ReBAC's versatility and effectiveness in managing access control in different settings.</p>
<h2 id="heading-advantages-of-rebac">Advantages of ReBAC</h2>
<p>Now, let's understand why Relationship-Based Access Control (ReBAC) stands out from traditional methods like Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC). ReBAC brings a host of benefits to the table, enhancing scalability, flexibility, and adaptability in complex organizational setups. Let's take a closer look at its key advantages:</p>
<h3 id="heading-granular-and-contextual-control">Granular and Contextual Control</h3>
<p>ReBAC allows organizations to define granular access controls tailored to the specific relationships between users, resources, and entities. This ensures that permissions are contextually relevant, providing a nuanced level of control.</p>
<h3 id="heading-efficient-management-of-hierarchies">Efficient Management of Hierarchies</h3>
<p>In scenarios with hierarchical structures, ReBAC simplifies the management of access control. By allowing permissions to be inherited based on relationships, it reduces the need for manual role assignments. </p>
<p>This simplifies the creation of natural connections between different business units, resources, and entities, making it easier to navigate complex hierarchies.</p>
<h3 id="heading-scalability-and-adaptability">Scalability and Adaptability</h3>
<p>ReBAC is designed to scale with organizational growth and changes in relationships. It easily accommodates the introduction of new entities or connections. However, it's crucial to address the challenge of role explosion, where the number of roles grows exponentially alongside asset growth. </p>
<p>Without proper management, this can lead to security risks and administrative overhead. Yet, ReBAC's scalability ensures that access controls remain effective, mitigating these challenges and avoiding the need for extensive modifications.</p>
<p>With these advantages in mind, ReBAC offers a robust framework for access control that meets the evolving needs of modern organizations. Now, let's delve into the common Relationship Type Permission Models to further understand how ReBAC operates.</p>
<h2 id="heading-common-relationship-type-permission-models">Common Relationship Type Permission Models</h2>
<p>Let’s look at the some of the permission models:</p>
<h3 id="heading-ownership-model"><strong>Owners</strong>hip Model</h3>
<p>The Ownership Model in ReBAC is a fundamental concept where ownership relationships streamline authorization within hierarchical structures.</p>
<p>In this model, the act of owning a higher-level entity automatically extends ownership over its subordinate entities.</p>
<p>Imagine a scenario in a cloud storage platform where users create folders to organize their files. In the Ownership Model, the user who creates a folder is designated as the owner.</p>
<p>Consequently, this ownership relation automatically grants the user ownership permissions for all files within that folder.</p>
<p>This hierarchical ownership structure simplifies permission management and mirrors real-world ownership dynamics.</p>
<h3 id="heading-parent-child-amp-hierarchical-model"><strong>Parent-Child &amp; Hierarc</strong>hical Model</h3>
<p>The Parent-Child &amp; Hierarchical Model is a powerful tool for managing access control in hierarchical structures such as organizational frameworks or file systems.</p>
<p>In this model, permissions granted at the parent level down to its child entities, ensuring a cohesive and efficient authorization system.</p>
<p>Consider a corporate environment where organizations have multiple departments. Using ReBAC's Parent-Child &amp; Hierarchical Model, permissions granted at the organization level, such as admin privileges, seamlessly extend to the organization's departments and their respective members.</p>
<p>This hierarchical flow of permissions reflects the organizational structure, making it easy to manage access control across different levels.</p>
<h3 id="heading-user-groups-amp-teams-model">User Groups &amp; Teams Model</h3>
<p>The User Groups &amp; Teams Model allows for efficient permission management by grouping users based on shared attributes or project affiliations.</p>
<p>In this model, permissions assigned to a group leader, for instance, can be effortlessly applied to all members of that group.</p>
<p>In a collaborative project management tool, teams serve as user groups. Applying ReBAC's User Groups &amp; Teams Model, the team lead's permissions, like editing or deleting project tasks, can be automatically inherited by all team members.</p>
<p>This streamlined approach simplifies access control in collaborative environments, where team-based permissions are crucial for project efficiency.</p>
<p>These three Relationship-Based Access Control models demonstrate the flexibility and adaptability of ReBAC in handling diverse organizational structures and application domains.</p>
<p>By aligning permissions with inherent relationships among entities, ReBAC provides an intuitive and powerful access control framework.</p>
<h2 id="heading-how-to-implement-rebac-with-permify">How to Implement ReBAC with Permify</h2>
<p>Now, let's practically implement ReBAC using Permify.</p>
<p><a target="_blank" href="https://permify.co/">Permify</a> is an open-source authorization as a service platform that allows developers to model, manage, and enforce access control in applications. It provides tools for defining complex authorization rules and relationships between entities, such as users, organizations, and resources.</p>
<p>Permify uses a domain-specific language for creating authorization models and offers a Playground environment for testing these models.</p>
<p>It also supports the creation of relational tuples and attributes for managing dynamic access control scenarios, streamlining the process of implementing robust and flexible authorization systems in software applications.</p>
<p>We'll create a scenario covering both Ownership and Parent-Child &amp; Hierarchical models.</p>
<p>We'll use the <a target="_blank" href="https://play.permify.co/">Permify Playground</a> for modeling.</p>
<h3 id="heading-modeling">Modeling</h3>
<p>Modeling in Permify involves creating a schema that defines the relationships and permissions between different entities in your system. </p>
<p>Here's a simplified process:</p>
<ol>
<li><strong>Define Entities</strong>: Start by creating entities that represent the resources in your system (for example: users, organizations, teams).</li>
<li><strong>Define Relations</strong>: Establish relationships between these entities. For example, an organization can have members and admins, or a team can be part of an organization.</li>
<li><strong>Define Actions and Permissions</strong>: Specify the actions that can be performed on each entity and the conditions under which they are allowed. For example, only admins can delete an organization.</li>
</ol>
<p>Permify uses its own language for modeling authorization logic, allowing for complex structures using set-algebraic operators. The modeling process includes defining entities, relations, actions, permissions, and, if needed, attributes for more advanced scenarios like ABAC (Attribute-Based Access Control).</p>
<p>Modeling in Permify is about creating a clear blueprint of your organization's structure and defining who gets to do what. </p>
<p>Let's break down how to model a schema in Permify.</p>
<h3 id="heading-step-1-define-entities">Step 1: Define Entities</h3>
<p>Entities are the core objects in your model. In this case, we have <code>user</code>, <code>organization</code>, <code>department</code>, <code>project</code>, <code>file</code>, and <code>task</code>.</p>
<pre><code class="lang-jsx">entity user {}
entity organization {}
entity department {}
entity project {}
entity file {}
entity task {}
</code></pre>
<h3 id="heading-step-2-establish-relationships">Step 2: Establish Relationships</h3>
<p>Next, we specify relationships between these entities. This defines how they are connected.</p>
<p><strong>Organization</strong>:</p>
<ul>
<li>Has <code>admin</code> who are users.</li>
</ul>
<pre><code class="lang-jsx">entity organization {
    relation admin @user
}
</code></pre>
<p><strong>Department</strong>:</p>
<ul>
<li>Belongs to an <code>organization</code> (parent).</li>
<li>Has <code>head</code>, <code>manager</code>, and <code>employee</code> roles, all of which are users.</li>
</ul>
<pre><code class="lang-jsx">entity department {
    relation parent @organization
    relation head @user
    relation manager @user
    relation employee @user
}
</code></pre>
<p><strong>Project</strong>:</p>
<ul>
<li>Belongs to a <code>department</code> (parent).</li>
</ul>
<pre><code class="lang-jsx">entity project {
    relation parent @department
}
</code></pre>
<p><strong>File</strong>:</p>
<ul>
<li>Belongs to a <code>department</code> (parent).</li>
<li>Has an <code>owner</code> who is a user.</li>
</ul>
<pre><code class="lang-jsx">entity file {
    relation parent @department
    relation owner @user
}
</code></pre>
<p><strong>Task</strong>:</p>
<ul>
<li>Belongs to a <code>project</code> (parent).</li>
<li>Has an <code>assignee</code> who is a user.</li>
</ul>
<pre><code class="lang-jsx">entity task {
    relation parent @project
    relation assignee @user
}
</code></pre>
<h3 id="heading-step-3-define-permissions">Step 3: Define Permissions</h3>
<p>Permissions determine what actions specific roles can perform on each entity.</p>
<p><strong>Project</strong>:</p>
<ul>
<li><code>contribute_to_project</code> permission is granted to <code>employee</code> or <code>manager</code> of the parent <code>department</code>.</li>
</ul>
<pre><code class="lang-jsx">entity project {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission contribute_to_project = parent.employee or parent.manager
}
</code></pre>
<p><strong>File</strong>:</p>
<ul>
<li><code>read</code>, <code>edit</code>, and <code>delete</code> permissions are controlled based on the <code>manager</code> of the parent <code>department</code> and the <code>owner</code>.</li>
</ul>
<pre><code class="lang-jsx">entity file {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission read   = parent.manager or owner
    permission edit   = parent.manager or owner
    permission <span class="hljs-keyword">delete</span> = owner
}
</code></pre>
<p><strong>Task</strong>:</p>
<ul>
<li><code>view_task</code> permission is given to the <code>assignee</code>.</li>
</ul>
<pre><code class="lang-jsx">entity task {
    <span class="hljs-comment">// ... (existing relations)</span>
    permission view_task = assignee
}
</code></pre>
<p><strong>Full Schema:</strong></p>
<pre><code><span class="hljs-comment">// Define entities</span>
entity user {}

entity organization {
    <span class="hljs-comment">// Organizational roles</span>
    relation admin @user
}

entity department {
    <span class="hljs-comment">// Department roles</span>
    relation parent @organization
    relation head @user
    relation manager @user
    relation employee @user
}

entity project {
    <span class="hljs-comment">// Project roles</span>
    relation parent @department

    <span class="hljs-comment">// Permissions</span>
    permission contribute_to_project = parent.employee or parent.manager
}

entity file {
    <span class="hljs-comment">// Represents files' parent entity (department)</span>
    relation parent @department

    <span class="hljs-comment">// Represents the owner of the file</span>
    relation owner @user

    <span class="hljs-comment">// Permissions</span>
    permission read   = parent.manager or owner
    permission edit   = parent.manager or owner
    permission <span class="hljs-keyword">delete</span> = owner
}

entity task {
    <span class="hljs-comment">// Represents tasks' parent entity (project)</span>
    relation parent @project

    <span class="hljs-comment">// Represents the assignee of the task</span>
    relation assignee @user

    <span class="hljs-comment">// Permissions</span>
    permission view_task   = assignee
}
</code></pre><h3 id="heading-relation-tuples">Relation Tuples</h3>
<p>The creation of relation tuples for the organization schema can be accomplished through the Permify Playground and API. </p>
<p>Here's how the relationship tuples would be structured according to the schema:</p>
<h4 id="heading-user-and-organization-relationships">User and Organization Relationships:</h4>
<ul>
<li>For assigning a user as an admin in an organization, the tuple would be: <code>organization:ID#admin@user:ID</code>.</li>
<li>To denote a user as a member of an organization: <code>organization:ID#member@user:ID</code>.</li>
</ul>
<h4 id="heading-user-and-department-relationships">User and Department Relationships:</h4>
<ul>
<li>Assigning a head to a department: <code>department:ID#head@user:ID</code>.</li>
<li>Assigning a manager to a department: <code>department:ID#manager@user:ID</code>.</li>
<li>Associating an employee with a department: <code>department:ID#employee@user:ID</code>.</li>
<li>To set a department's parent organization: <code>department:ID#parent@organization:ID</code>.</li>
</ul>
<h4 id="heading-project-and-department-relationships">Project and Department Relationships:</h4>
<ul>
<li>To define the parent department of a project: <code>project:ID#parent@department:ID</code>.</li>
</ul>
<h4 id="heading-file-management">File Management:</h4>
<ul>
<li>Associating a file with its parent department: <code>file:ID#parent@department:ID</code>.</li>
<li>Defining the owner of a file: <code>file:ID#owner@user:ID</code>.</li>
</ul>
<h4 id="heading-task-management">Task Management:</h4>
<ul>
<li>Linking a task to its parent project: <code>task:ID#parent@project:ID</code>.</li>
<li>Assigning a user as the assignee of a task: <code>task:ID#assignee@user:ID</code>.</li>
</ul>
<p>In each of these tuples, <code>ID</code> is a placeholder that should be replaced with the actual identifier of the entity or user in your system. </p>
<p>For instance, if you have an organization with an ID of 1 and a user with an ID of 3, and you want to assign this user as an admin of that organization, the tuple would be <code>organization:1#admin@user:3</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Untitled-2.png" alt="Untitled" width="600" height="400" loading="lazy">
<em>Relationships dashboard</em></p>
<p>These tuples are created and managed using the Permify API. The API allows for creating, updating, and deleting these tuples as needed, reflecting the dynamic nature of relationships and permissions in an organization. This flexibility ensures that your authorization data is always up-to-date and consistent with the current state of your system's entities and their relationships.</p>
<h3 id="heading-enforcement">Enforcement</h3>
<p>To enforce access control in your schema using Permify, you can create scenarios in the Permify Playground's Enforcement section. This is done using YAML to define various test scenarios. </p>
<p>Here's an example based on your schema and the created relation tuples:</p>
<h4 id="heading-check-if-a-user-for-example-user2-can-contribute-to-a-project">Check if a user (for example: user:2) can contribute to a project:</h4>
<ul>
<li>Entity: <code>project:1</code></li>
<li>Subject: <code>user:2</code></li>
<li>Assertion: <code>contribute_to_project: true or false</code> (depending on whether user:2 is an employee or manager in the parent department of project:1).</li>
</ul>
<pre><code>- name: user_access_test
  <span class="hljs-attr">checks</span>:
    - entity: project:<span class="hljs-number">1</span>
      <span class="hljs-attr">subject</span>: user:<span class="hljs-number">2</span>
      <span class="hljs-attr">context</span>: <span class="hljs-literal">null</span>
      <span class="hljs-attr">assertions</span>:
        contribute_to_project: <span class="hljs-literal">false</span>
  <span class="hljs-attr">entity_filters</span>: []
  <span class="hljs-attr">subject_filters</span>: []
</code></pre><p><strong>Check if a user (for example: user:4) can view a task</strong>:</p>
<ul>
<li>Entity: <code>task:1</code></li>
<li>Subject: <code>user:4</code></li>
<li>Assertion: <code>view_task: true or false</code> (true if user:4 is the assignee of the task).</li>
</ul>
<pre><code>- name: user_access_test
  <span class="hljs-attr">checks</span>:
    - entity: task:<span class="hljs-number">1</span>
      <span class="hljs-attr">subject</span>: user:<span class="hljs-number">4</span>
      <span class="hljs-attr">context</span>: <span class="hljs-literal">null</span>
      <span class="hljs-attr">assertions</span>:
        view_task: <span class="hljs-literal">false</span>
  <span class="hljs-attr">entity_filters</span>: []
  <span class="hljs-attr">subject_filters</span>: []
</code></pre><p>These scenarios will help you validate the permissions as per your schema in a controlled environment. </p>
<p>Each assertion in the YAML scenario will define the expected outcome (true or false) for a particular action or permission based on your schema and data tuples.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Untitled-1.png" alt="Untitled" width="600" height="400" loading="lazy">
<em>YAML representation</em></p>
<p>For detailed steps and examples, refer to the <a target="_blank" href="https://docs.permify.co/docs/getting-started/modeling/">Permify Modeling Documentation</a>.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By following these steps, you can effectively implement a sophisticated ReBAC system using Permify. </p>
<p>This implementation will provide a robust, flexible, and secure access control framework tailored to the unique needs and relationships within your organization.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Databases Guarantee Isolation – Pessimistic vs Optimistic Concurrency Control Explained ]]>
                </title>
                <description>
                    <![CDATA[ ACID (Atomicity, Consistency, Isolation, and Durability) is a set of guarantees when working with a DBMS. Pessimistic and optimistic concurrency control explains how databases achieve the “I” in ACID. Isolation is a guarantee that concurrently runnin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-databases-guarantee-isolation/</link>
                <guid isPermaLink="false">66d45e12f855545810e93431</guid>
                
                    <category>
                        <![CDATA[ concurrency ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Adetunji ]]>
                </dc:creator>
                <pubDate>Mon, 05 Feb 2024 22:41:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>ACID (Atomicity, Consistency, Isolation, and Durability) is a set of guarantees when working with a DBMS. Pessimistic and optimistic concurrency control explains how databases achieve the “I” in ACID.</p>
<p>Isolation is a guarantee that concurrently running transactions should not interfere with each other. This is arguably the most important ACID property, because different DBMS can often have different default isolation levels. And you may need to change this based on what is needed for your application.</p>
<p>In a <a target="_blank" href="https://lightcloud.substack.com/p/acid-databases-explained">previous article</a>, I explained the two main isolation levels used by most DBMS. These are the <a target="_blank" href="https://lightcloud.substack.com/i/140524854/read-committed">read committed</a> and <a target="_blank" href="https://lightcloud.substack.com/i/140524854/repeatable-read">repeatable read</a> isolation levels.</p>
<p>Pessimistic and optimistic concurrency controls essentially explain some of the ways a database is able to achieve these two isolation guarantees.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-pessimistic-concurrency-control">Pessimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-library-analogy-for-pessimistic-concurrency-control">Pessimistic Concurrency Control Analogy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-simple-real-world-example-of-pessimistic-concurrency-control-in-action">Real-World Example of Pessimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-and-challenges-of-pessimistic-concurrency-control">Pros and Cons of Pessimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-pessimistic-concurrency-controls-guarantee-the-read-committed-isolation-level">How it Guarantees the Read Committed Isolation Level</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-optimistic-concurrency-control">Optimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-simple-real-world-example-of-optimistic-concurrency-control-in-action">Real-World Example of Optimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-and-challenges-of-optimistic-concurrency-control">Pros and Cons of Optimistic Concurrency Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-optimistic-concurrency-controls-guarantee-the-repeatable-read-isolation-level">How it Guarantees the Repeatable Read Isolation Level</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-bringing-it-together">Bringing it Together</a></p>
</li>
</ol>
<h2 id="heading-pessimistic-concurrency-control">Pessimistic Concurrency Control</h2>
<p>With pessimistic concurrency control, the DBMS assumes that conflicts between transactions are likely to occur. It is pessimistic – that is, it assumes that if something can go wrong, it will go wrong. This pessimism prevents conflicts from occurring by blocking them before they get a chance to start.</p>
<p>To prevent these conflicts, it <em>locks</em> the data that a transaction is using until the transaction is completed. This approach is 'pessimistic' because it assumes the worst-case scenario – that every transaction might lead to a <em>conflict</em>. The data is therefore locked in order to prevent conflicts from happening.</p>
<p>I've mentioned two technical terms here that need clarification: <em>locks</em> and <em>conflict</em>.</p>
<h3 id="heading-what-are-locks">What are locks?</h3>
<p>A lock is a mechanism used to control access to a database item, like a row or table. Locks ensure data integrity, if multiple transactions are occurring at the same time.</p>
<p>In very simple terms, a lock is analogous to a reservation on the database item. A reservation, be it a restaurant, hotel, or a train, prevents other people from using the resource you reserved for a fixed duration of time. Locks work in a similar way.</p>
<p>There are two types of locks: a read lock and a write lock.</p>
<p>A read lock can be shared by multiple transactions trying to read the same database item. But it blocks other transactions from updating that database item.</p>
<p>A write lock is exclusive – that is, it can only be held by a single transaction. A transaction with a write lock on a database item blocks every other transaction from reading or updating that database item.</p>
<h3 id="heading-what-are-conflicts">What are conflicts?</h3>
<p>A conflict refers to a situation where multiple transactions are attempting to access and modify the same data concurrently, in a way that could lead to inconsistencies or errors in the database.</p>
<h3 id="heading-a-library-analogy-for-pessimistic-concurrency-control">A Library Analogy for Pessimistic Concurrency Control</h3>
<p>First, let us describe an analogy for a write lock.</p>
<p>Imagine you're at a library, and you want to borrow a hard copy of a popular book, say, The Great Gatsby by F. Scott Fitzgerald.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd683922-af28-4886-a6dc-6c121ac7e915_1858x1054.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Write locks are analogous to borrowing a physical book from the library</em></p>
<p>With a write lock, the librarian assumes that there can be conflicts over who gets to borrow the book. So, they implement a strict rule to avoid conflicts: only one person can hold the reservation for a physical book at a time.</p>
<p>When you reserve the book, no one else can borrow it. The book is available to be reserved again only once it is returned. This is similar to how a write lock works.</p>
<p>Write locks are exclusive. This means that they can only he held by a single transaction at any time. Similarly, reserving a physical book from the library means no one else has access to it. Only the person with the reservation can read the book, or write in it (although writing in a library book is bad form).</p>
<p>Read locks work a bit differently.</p>
<p>A read lock is analogous to someone making a reservation to borrow an e-book. Borrowing an e-book is not a very popular thing to do, but some libraries do have such a service.</p>
<p>Many people can make the same reservation for the same e-book without any conflict. One person borrowing an e-book version of The Great Gatsby does not stop others from doing the same. But no one who borrows an e-book can update it, by scribbling notes in it that can be seen by others, for example.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb2c7acc-c32e-47f6-a412-2000ae14da2b_2156x1344.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Read locks are analogous to borrowing an e-book from the library</em></p>
<p>Pessimistic concurrency control is very safe because it prevents conflicts from occurring by blocking them before they get a chance to start. A write lock on a database item prevents other transactions from reading or updating that item while that lock is held, similar to to how a library stops more than one person from trying to borrow the same physical book at the same time.</p>
<p>A read lock on a database item allows other transactions to also obtain a read lock for that item, but prevents transactions from updating that item. This is analogous to borrowing an e-book, where multiple people can borrow the same e-book at the same time, but can’t make any updates to it.</p>
<h3 id="heading-a-simple-real-world-example-of-pessimistic-concurrency-control-in-action">A Simple Real-World Example of Pessimistic Concurrency Control in Action</h3>
<p>Let's illustrate how pessimistic concurrency control works using a simple example involving a bank balance database table. Assume we have a table named Accounts with the following columns: AccountID and Balance.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d9e2dd5-5abe-46ea-bbb6-033f1d5bc663_1096x534.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Database columns for AccountID and Balance</em></p>
<p>Two transactions, T1 and T2, intend to update the balance of account 12345. T1 wants to withdraw $300, and T2 wants to deposit $400. At the end of these two transactions, the account balance should read $1600</p>
<p>Here are the steps of how this will work using write locks:</p>
<ol>
<li><p>Start of T1 (Withdrawal): T1 requests to update the balance of AccountID 12345. The database system places an exclusive write lock on the row for AccountID 12345, preventing other transactions from reading or writing to this row until T1 is completed. T1 reads the balance ($1500).</p>
</li>
<li><p>T1 Processing: T1 calculates the new balance as $1200 ($1500 - $300).</p>
</li>
<li><p>Commit T1: T1 writes the new balance ($1200) back to the database. Upon successful commit, T1 releases the exclusive lock on AccountID 12345.</p>
</li>
<li><p>Start of T2 (Deposit) After T1 Completes: Now that T1 has completed and the lock is released, T2 can start. T2 attempts to read and update the balance for AccountID 12345. The database system places an exclusive lock on the row for AccountID 12345 for T2, ensuring no other transactions can interfere. T2 reads the updated balance ($1200).</p>
</li>
<li><p>T2 Processing: T2 calculates the new balance as $1600 ($1200 + $400).</p>
</li>
<li><p>Commit T2: T2 writes the new balance ($1600) back to the database. Upon successful commit, T2 releases the exclusive lock on AccountID 12345.</p>
</li>
<li><p>Result: The Accounts table is updated using locks After T1: $1200 After T2: $1600</p>
</li>
</ol>
<p>Without a write lock in this example, T1 and T2 could read the original balance of $1500 at the same time. So, instead of a balance of $1200 after T1 has committed, T2 still reads the original balance of $1500 and adds $400. This would cause the final balance to be $1500 + $400 = $1900 (instead of $1600).</p>
<p>Absence of locking has created free money, which is never a bad thing for a customer. But, if money can be conjured out of thin air because of these conflicts, it can also vanish, and accidentally shrinking bank balances are a quick way to make customers unhappy.</p>
<h3 id="heading-benefits-and-challenges-of-pessimistic-concurrency-control">Benefits and Challenges of Pessimistic Concurrency Control</h3>
<p>Just like reserving a book ensures that it's set aside for one person, pessimistic concurrency control locks data for a single transaction. Other transactions cannot access or modify this data until the lock is released.</p>
<p>This method prevents two people from trying to take out the same popular book at the same time, thereby avoiding disputes. Similarly, in databases, it stops conflicts due to concurrent transactions before they get a chance to start.</p>
<p>But this approach can be inefficient. The reserved book might sit on the reserved shelf for a while, stopping other people from reading it.</p>
<p>In databases, this locking mechanism can lead to underutilisation of resources and a slowdown in the speed transactions take to complete, since a subset of the data is locked and inaccessible to other transactions.</p>
<h3 id="heading-how-pessimistic-concurrency-controls-guarantee-the-read-committed-isolation-level">How Pessimistic Concurrency Controls Guarantee the Read Committed Isolation Level</h3>
<p>So, how exactly does pessimistic concurrency control work in ensuring the isolation guarantee, that is the “I” in ACID? The implementation details can vary across different DBMS. But the explanation here shows the general approach.</p>
<p>Recall that <a target="_blank" href="https://lightcloud.substack.com/i/140524854/read-committed">the read committed isolation</a> level prevents dirty writes and dirty reads.</p>
<h4 id="heading-preventing-dirty-writes">Preventing Dirty Writes</h4>
<p>Overwriting data that has already been written by another transaction but not yet committed is called a dirty write. A common approach to preventing dirty writes is to use pessimistic concurrency control. For example, by using a write lock at the row level.</p>
<p>When a transaction wants to modify a row, it acquires a lock on that row and holds it until the transaction is complete. Recall that write locks can only be held by a single transaction. This prevents another transaction from acquiring a lock to modify that row.</p>
<h4 id="heading-preventing-dirty-reads">Preventing Dirty Reads</h4>
<p>Reading data from another transaction that has not yet been committed is called a dirty read. Dirty reads are prevented using either a read or write lock. Once a transaction acquires a read lock on a database item, it will prevent updates to that item.</p>
<p>But what happens if you are trying to read something that is already being updated but the transaction has not yet committed? In this instance, the write lock saves the day again.</p>
<p>Since write locks are exclusive (can’t be shared with other transactions), any transaction wanting to read the same database item will have to wait until the transaction with the write lock is committed (or aborted, if it fails). This prevents other transactions from reading uncommitted changes.</p>
<h2 id="heading-optimistic-concurrency-control">Optimistic Concurrency Control</h2>
<p>With optimistic concurrency control, transactions do not obtain locks on data when they read or write. The "Optimistic" in the name comes from assuming that conflicts are unlikely to occur, so locks are not needed. If something does go wrong though, conflicts will still be prevented and everything will be OK.</p>
<p>Unlike pessimistic concurrency control – which prevents conflicts from occurring by blocking them before they get a chance to start – optimistic concurrency control checks for conflicts at the end of a transaction.</p>
<p>With optimistic concurrency control, multiple transactions can read or update the same database item without acquiring locks. How exactly does this work?</p>
<p>Every time a transaction wants to update a database item, say a row, it will also read two additional columns added to every table by the DBMS – the timestamp and the version number. Before that transaction is committed, it checks if another transaction has made any change(s) to that row by confirming if the version number and timestamp are the same.</p>
<p>If they have changed, that means another transaction has updated that row, so the initial transaction will have to be retried.</p>
<h3 id="heading-a-simple-real-world-example-of-optimistic-concurrency-control-in-action">A Simple Real-World Example of Optimistic Concurrency Control in Action</h3>
<p>Let's illustrate how optimistic concurrency control works using a simple example involving a bank balance database table. Assume we have a table named Accounts with the following columns: AccountID, Balance, VersionNumber, and Timestamp.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc46a7d00-c1b9-46c6-80c0-0bc1a7aba9ae_2180x542.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Table showing AccountID, Balance, VersionNumber, and Timestamp columns</em></p>
<p>Two transactions, T1 and T2, intend to update the balance of account 12345 at the same time. T1 wants to withdraw $200, and T2 wants to deposit $300. At the end of these two transactions, the account balance should read $1100</p>
<p>Here are the steps of how this will work:</p>
<ol>
<li><p>Start of Transactions: T1 reads the balance, version number, and timestamp for AccountID 12345. Simultaneously, T2 reads the same row with the same balance, version number, and timestamp.</p>
</li>
<li><p>Processing: T1 calculates the new balance as $800 ($1000 - $200) but does not write it back immediately. T2 calculates the new balance as $1300 ($1000 + $300) but also waits to commit.</p>
</li>
<li><p>Attempt to Commit T1: Before committing, T1 checks the current VersionNumber and Timestamp of AccountID 12345 in the database. Since no other transaction has modified the row, T1 updates the balance to $800, increments the VersionNumber to 2, updates the Timestamp, and commits successfully.</p>
</li>
<li><p>Attempt to Commit T2: T2 attempts to commit by first verifying the VersionNumber and Timestamp. T2 finds that the VersionNumber and Timestamp have changed (now VersionNumber is 2, and Timestamp is updated), indicating another transaction (T1) has updated the row. Since the version number and timestamp have changed, T2 realises there was a conflict.</p>
</li>
<li><p>Resolution for T2: T2 must restart its transaction. It re-reads the updated balance of $800, the new VersionNumber 2, and the updated Timestamp. T2 recalculates the new balance as $1100 ($800 + $300), updates the VersionNumber to 3, updates the Timestamp, and commits successfully.</p>
</li>
</ol>
<p>Result: The Accounts table is updated sequentially and safely without any locks: After T1: $800, VersionNumber: 2. After T2: $1100, VersionNumber: 3.</p>
<h3 id="heading-benefits-and-challenges-of-optimistic-concurrency-control">Benefits and Challenges of Optimistic Concurrency Control</h3>
<p>On the positive side, avoiding locks allows for high levels of concurrency. This is particularly beneficial in read-heavy workloads where transactions are less likely to conflict, allowing the system to handle more transactions in a given period. For example, database backups and analytical queries typically used in a data warehouse.</p>
<p>But in scenarios where conflicts are frequent, the cost of repeatedly rolling back and retrying transactions can outweigh the benefits of avoiding locks, making optimistic concurrency control less efficient</p>
<h3 id="heading-how-optimistic-concurrency-controls-guarantee-the-repeatable-read-isolation-level">How Optimistic Concurrency Controls Guarantee the Repeatable Read Isolation level</h3>
<p>The repeatable read is more strict isolation level in that it has the same guarantees as read committed isolation, plus it guarantees that reads are repeatable.</p>
<p>A repeatable read guarantees that if a transaction reads a row of data, any subsequent reads of that same row of data within the same transaction will yield the same result, regardless of changes made by other transactions. This consistency is maintained throughout the duration of the transaction.</p>
<p>How can a repeatable read be achieved? Pessimistic control using a read lock can help with this, since a transaction with a read lock on a database item will prevent that item from being updated. But this can be inefficient, since a long running read transaction can block updates from happening to that database item.</p>
<p>Multi-Version Concurrency Control (MVCC) is a concurrency control method used by some DBMS to allow multiple transactions to access the same data simultaneously without locking the data. This makes it a popular choice for reducing lock contention and improving the scalability of databases.</p>
<p>MVCC achieves this by keeping multiple versions of data objects, which helps to manage different visibility levels for transactions depending on their timestamps or version numbers.</p>
<h2 id="heading-bringing-it-together">Bringing it Together</h2>
<p>A lock is a mechanism used to control access to a database item, like a row or table. In very simple terms, it is analogous to a reservation on a database item.</p>
<p>Pessimistic concurrency control assumes the worst. It assumes that conflicts are likely to happen, so locks are used to block transactions that can cause conflicts before they even get a chance to start.</p>
<p>In situations where conflicts are common, such as a write heavy application, this approach can prevent the overhead associated with frequent rollbacks and retries (which happens in optimistic concurrency control) by ensuring exclusive access to database items during transactions.</p>
<p>Optimistic concurrency control assumes the best. It assumes that conflicts are unlikely to occur, so locks are not needed to stop transactions before they start. Instead, potential conflicts are checked at the end of a transaction and if any are found, the transaction is aborted or retried.</p>
<p>Optimistic concurrency control is useful for read heavy transactions with infrequent writes, as it allows multiple transactions to proceed without the need to use a lock, which can be inefficient.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Back Up and Restore Azure SQL Databases ]]>
                </title>
                <description>
                    <![CDATA[ Microsoft's Azure provides many services via a single cloud, which lets them offer one solution for multiple corporate infrastructures. Development teams often use Azure because they value the opportunity to run SQL databases in the cloud and complet... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-back-up-and-restore-sql-azure-database/</link>
                <guid isPermaLink="false">66ba2f06d8f1b6513f67389b</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Backup ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Tray ]]>
                </dc:creator>
                <pubDate>Wed, 24 Jan 2024 22:34:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/maxresdefault.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Microsoft's Azure provides many services via a single cloud, which lets them offer one solution for multiple corporate infrastructures. Development teams often use Azure because they value the opportunity to run SQL databases in the cloud and complete simple operations via the Azure portal. </p>
<p>But you'll need to have a way to back up your data, as it's crucial to ensuring the functionality of the production site and the stability of everyday workflows. So creating Azure SQL backups can help you and your team avoid data loss emergencies and have the shortest possible downtime while maintaining control over the <a target="_blank" href="https://www.hostpapa.com/blog/technology/what-is-an-it-infrastructure/">infrastructure</a>.</p>
<p>Another reason to have a current Azure database backup is Microsoft’s policy. Microsoft uses the shared responsibility model, which makes the user responsible for data integrity and recovery while Microsoft only ensures the availability of its services. Microsoft directly recommends using third-party solutions to create database backups. </p>
<p>In case you run a local SQL Server, you'll need to prepare for the possibility of hardware failures that may result in data loss and downtime. An SQL database on Azure helps mitigate that risk, although it's still prone to human errors or cloud-specific threats like malware. </p>
<p>These and other threats make enabling Azure SQL database backups necessary for any organization using Microsoft’s service to manage and process data. </p>
<p>In this tutorial, you'll learn about backing up Azure databases and restoring your data on demand with native instruments provided by Microsoft, including methods like: </p>
<ul>
<li>Built-in Azure database backup functionality</li>
<li>Cloud archiving</li>
<li>Secondary database and table management</li>
<li>Linked server</li>
<li>Stretch Database</li>
</ul>
<h2 id="heading-why-backup-your-sql-azure-database">Why Backup Your SQL Azure Database?</h2>
<p>Although I covered this briefly in the intro, there are many reasons to back up your SQL Azure database data. </p>
<h3 id="heading-disaster-recovery">Disaster Recovery</h3>
<p>Data centers can be damaged or destroyed by planned cyberattacks, random malware infiltration (<a target="_blank" href="https://www.nakivo.com/blog/how-to-protect-against-ransomware-attacks/">check out this article</a> to discover more on ransomware protection), and natural disasters like floods or hurricanes, among others. Backups can be used to swiftly recover data and restore operations after various disaster cases.</p>
<h3 id="heading-data-loss-prevention">Data Loss Prevention</h3>
<p>Data corruption, hardware failure, and accidental or malicious deletion lead to data loss and can threaten an organization. Backup workflows set up to run regularly mean you can quickly recover the data that was lost or corrupted.</p>
<h3 id="heading-compliance-and-regulations">Compliance and Regulations</h3>
<p>Compliance requirements and legislative regulations can be severe regardless of your organization’s industry. Mostly, laws require you to keep up with security and perform regular backups for compliance.</p>
<h3 id="heading-testing-and-development">Testing and Development</h3>
<p>You can use backups to create Azure database copies for development, troubleshooting, or testing. Thus, you can fix, develop, or improve your organization’s workflows without involving the production environment.</p>
<h2 id="heading-how-to-back-up-your-azure-sql-database">How to Back Up Your Azure SQL Database</h2>
<p>Backing up your Azure SQL database can be challenging if you go through the process without preparation. So that's why I wrote this guide – to help you be prepared. Here's what we'll cover in the following sections:</p>
<ul>
<li>Requirements for SQL Azure database backup</li>
<li>How to configure database backups in Azure with native tools</li>
<li>Cloud archiving</li>
<li>Backup verification and data restoration</li>
</ul>
<h3 id="heading-sql-azure-database-backup-requirements">SQL Azure Database Backup Requirements</h3>
<p>Before backing up your SQL Azure databases, you need to create and configure Azure storage. Before you do that, you'll need to go through the following steps:</p>
<p>First, open the Azure management portal and find <strong>Create a Resource</strong>.</p>
<p>Then, go to <strong>Storage</strong> &gt; <strong>Storage account</strong>. Provide the information, including the location and names of a storage account and resource group according to your preferences. After you enter the information, hit <strong>Next</strong>.</p>
<p><img src="https://lh7-us.googleusercontent.com/TbuVyIRHXKkKd1__mMSo8RJTktZVnJjK2r8ijtY1h5gvlY5KqkRE8NPsej18m-A1-p3UwF-YO0W0p9AzJa8AW7TwR1yXp531y7qXrm84hJQIuTIKUMwhbnU7WAiUoGRPIdL_SrQCv0nxav4RnCu389o" alt="Image" width="600" height="400" loading="lazy">
<em>Storage account config</em></p>
<p>Then go to the advanced section for additional settings. The optimal choice is to set _"_Secure transfer required" as <strong>Enabled</strong> and "Allow access" from <strong>All</strong> networks. For more resilience in case of human error, you can set "Blob soft delete" as <strong>Enabled</strong>. With that setting, you can quickly correct accidental deletions in the storage account.</p>
<p>After that, specify the tags you need to simplify navigating through your infrastructure.</p>
<p><img src="https://lh7-us.googleusercontent.com/BTXJpa8dz9wKa7p9pQm84fmtqtwD5WEuRB9yh2_Htpa-pF86Zf70CuKP7j32uPR56igplljn6fehCuJEgnMkiCiAcZPZVU_FNEL2JZcrtVjunthzLKQOWp9wbtXLLLKMgYTerYNJpsiQxZjJcMlr05I" alt="Image" width="600" height="400" loading="lazy">
<em>Azure backup storage tags</em></p>
<p>Check the settings once more. If everything is configured correctly, hit <strong>Create</strong>. Your new storage account is now created.</p>
<p>Once the storage volume is created, it's time to configure a backup data storage container. </p>
<p>Go to the storage account, find <strong>Containers</strong>, then hit the <strong>+ Container</strong> tab there. After that, specify a name for the new container and switch Public access level to <strong>Private (no anonymous access)</strong>.</p>
<p><img src="https://lh7-us.googleusercontent.com/eGTyBc9-uiRO52QsQ0pGzlWPAZlvyMR0miExCMX-Pck9yPQvUlwKqa0_N-zWc908TzHONdzLC2Kv8ACU5UHJjuJ8G6kBOmgxONkLN5LE33ItBsKOx5XdIKtMg8oYDY6eKrdFrZ0bhuOD535QALtqxMU" alt="Image" width="600" height="400" loading="lazy">
<em>Container Azure storage account</em></p>
<p>You can then use the container as a backup storage (.bak files will be stored there in that case).</p>
<h2 id="heading-azure-database-backup-configuration">Azure Database Backup Configuration</h2>
<p>Now, everything is set up for you to back up your SQL Azure database. Do the following to create a database backup:</p>
<p>First, go to <strong>SQL Management Studio</strong>, and establish a connection with the SQL server. After that, right-click the database that should be backed up. The context menu appears, so go to <strong>Tasks</strong> there. Then hit <strong>Back Up…</strong>. </p>
<p><img src="https://lh7-us.googleusercontent.com/l5g6ajoZ6ZuBObluCiG7mra9pz9BPgP-iOCAoGh36SY5zfg1yv300oQQ1cvgrVFNL75Nu7roFIVp2BfPze3ag5nTzL1NQYiO_fhUokWSd9fVms1SDcoP5pJ7a4wWdB3fQJWeKbrNIK_-vo2-hiXTDl0" alt="Image" width="600" height="400" loading="lazy">
<em>SQL server tasks backup</em></p>
<p>Then find the Destination tab, and set <strong>Back up to line to URL</strong> there. After that, hit <strong>New container</strong>.</p>
<p>Next, sign in to Azure. Pick the container you created before. Provide your credentials, then hit <strong>OK</strong>.</p>
<p>You’ll see a message asking you to sign in to Azure subscription. Then, choose the container and hit <strong>OK</strong>.</p>
<p>Now, you'll see the configured backup destination URL listed. To start the workflow to back up your Azure data, hit <strong>OK</strong> once again.</p>
<p>When your SQL Azure database backup is completed, the message shows up: "<em>The backup of database ‘your database name’ completed successfully</em>."</p>
<p>The backup file in the target container should now be visible from the Azure portal.</p>
<p>Keep in mind that, when uploading backups to any cloud storage, you may face issues if your network connection is not fast enough. </p>
<p>In case that’s true for you, you can reorganize your backup workflows: send backup data to a physical storage drive first, and then send another copy to the cloud. Thus, you can prevent operational challenges that might appear due to network bandwidth deficiency.</p>
<h2 id="heading-cloud-archiving-for-azure-database-backups">Cloud Archiving for Azure Database Backups</h2>
<p>Databases tend to grow in volume as the organization grows. This means that the storage space required to fit the data and that data's backup increases significantly. Also, the original data volume prolongs the duration of full backup workflows, posing another challenge. </p>
<p>Of course, the first way to get more storage space is to revise your data regularly and erase records that are irrelevant, outdated, or unnecessary otherwise. Still, it's sometimes difficult to determine if data will be or become unnecessary or irrelevant, especially when dealing with issues of compliance. </p>
<p>To keep your organization compliant in any case, data archiving can help you solve two problems at once: you can ensure data accessibility on one hand, and save storage space on the other hand.</p>
<p>To archive your SQL database in the cloud, you should first save that database copy to an Azure blob container. Then, to move a newly created blob to the archive tier in the Azure portal, do the following: </p>
<ol>
<li>Go to the required container where the SQL database is stored.</li>
<li>Choose the blob that you need to move.</li>
<li>Hit <strong>Change tier</strong>.</li>
</ol>
<p><img src="https://lh7-us.googleusercontent.com/p41GC9ys42mQBQGWW1jqcR2xCfACpCYF1MpGG7Qx6EdqzjDSK6xnuqlPRCtDuhEmH_-8E6Lz2gY8H3h1CoZ4_jpScQWUxB-21GXOnuDEBSHVJiGa1zBiHu4JJP2Xntq1fpbPLjbb1-APOTJMO2sdBMk" alt="Image" width="600" height="400" loading="lazy">
<em>Azure blob container change tier</em></p>
<ol start="4">
<li>In the <strong>Access tier</strong> dropdown menu, choose <strong>Archive</strong>.</li>
</ol>
<p><img src="https://lh7-us.googleusercontent.com/qlyKGop3uj6kfi71fSpVsqKkhf8vc1TiQRyoeHEiwjKdg1i3Dsz_LXLHcD5q-qR77utIPUbkLyWU7Xzn7ehl3Z1IWUQZjy0LndXLEcDA1PRZj4ufO8QGR0GCmEDGqoWQ6paFwo8pn0VbUH8RWjlRzLU" alt="Image" width="600" height="400" loading="lazy">
<em>Azure blob change tier</em></p>
<ol start="5">
<li>Hit <strong>Save</strong>.</li>
</ol>
<p>Additionally, the Archive storage tier is the most affordable one in Azure, meaning that you can reduce your database data TCO with it.</p>
<h3 id="heading-secondary-database-and-table-management">Secondary Database and Table Management</h3>
<p>There exist several workflows that can help you set up Azure database backup archiving for your organization. When you need the data to stay in the initial database, for instance, creating a separate table and moving that data there can be your choice. However, the filegroup of that table should stay apart from the main database and be moved to a separate disk whenever possible. </p>
<p>Most probably, you’ll want to let users access the data you send to a separate table. To make that happen, you can create a view merging the relevant tables and redirect the requests to that view, not to the original table. Doing things that way, you can keep the data accessible while dealing with maintenance faster.</p>
<h3 id="heading-sql-server-linking">SQL Server Linking</h3>
<p>If you can’t move the data to another database for internal reasons such as special Azure backup policies, you can consider maintaining your primary database accordingly. </p>
<p>Here, the outcome is likely to be that of the previous case, but you need to link the SQL servers or configure apps so they can send direct requests to your second server. </p>
<p>The downside here is that your SQL database, which was supposed to be a backup one, becomes a production database and gains appropriate importance for an organization.</p>
<p>There are two ways to create linked servers via SQL Server Management Studio (SSMS): </p>
<ul>
<li><strong>sp_addlinkedserver</strong> (Transact-SQL) system stored procedure that creates a linked server</li>
<li><strong>SSMS GUI</strong></li>
</ul>
<p>After you've ensured that you have appropriate access rights on both server instances you need to link, the network is configured appropriately to access them, and SSMS is installed, you'll need to go through the following steps:</p>
<p>First, open SSMS.</p>
<p><img src="https://lh7-us.googleusercontent.com/6NS8wE2UmtV5Bs3-loE7kIASfehk4-hSaPP5y7Wm1oEVIUFDCPyxD_f1rLQzxsJVdCGaFJwcRHqKVrnypgETOSohLP5hQK50m4tj4pBZBIx6oTUj8WOJbcttfhy0IybUyC_CrJCyK8saEPnchKInp7g" alt="Image" width="600" height="400" loading="lazy">
<em>Microsoft SSMS</em></p>
<p>Connect to the instance where you need to establish a linked server. Then find <strong>Object Explorer &gt; Server Objects</strong>, then right-click <strong>Linked Servers</strong>.</p>
<p>Pick <strong>New Linked Server</strong> from the dropdown:</p>
<p><img src="https://lh7-us.googleusercontent.com/tD5YO2e1RtfLUmtBdRFNfiHQSyaxnQml9lBGnRPPzuNrW4Fcu-3alTg4N3-mdR-oQxcaUyMpyqp36l7r3aTfg29RzT6Jgx0Nb1eT2T-y-zotl1RujRUIC4gSwE25aslpfMJJUvNW4MMivP4BstyQu4o" alt="Image" width="600" height="400" loading="lazy">
<em>New linked server SSMS</em></p>
<p>Then configure the server properties, including name, server type, provider and product name:</p>
<p><img src="https://lh7-us.googleusercontent.com/y-WSzJni8uyKBAcJywPqk-iufIeJ_4TTs1rf3e_9RYhj1Kt8nUsZfad9Vekec4yL6eFCX8doLR4Qr7iA6X3p78jnRfIs3AYlHMn1GOhR8Ya29CW5X9DIU-nbj_jDaTwAvwEJXNjr7npd5THmnD7Iv3A" alt="Image" width="600" height="400" loading="lazy">
<em>Linked server configuration SSMS</em></p>
<p>Then you'll just need to complete the security configuration, set up the server options, and complete connection testing.</p>
<h3 id="heading-original-data-deletion">Original Data Deletion</h3>
<p>When you don’t need 24/7 data availability but need the data stored due to internal policies or compliance requirements, you can choose what's probably the simplest solution to increase storage space efficiency. Just back up the data that can stay unavailable and then delete the originals from the main database. Accessing any records you may need will still be possible via the backup.</p>
<h3 id="heading-stretch-database">Stretch Database</h3>
<p>Aiming to make data management of organizations’ databases simpler, Microsoft implemented a Stretch Database feature in SQL Server 2016. With this feature, you can get an SQL backup to Azure after you send the data from the hosted database to an Azure SQL database. The method enables you to increase overall infrastructure cost-efficiency by simplifying backup workflows.</p>
<p>To enable this workflow in your environment, develop the policy specifying the data on a hosted server to send to Azure. You don’t need to introduce any changes in applications that use the production database: SQL Server can independently get the records from the Azure SQL Database.</p>
<h3 id="heading-azure-database-backups-verification-and-restoration">Azure Database Backups Verification and Restoration</h3>
<p>During an SQL Azure database backup, you can choose to create such backups <strong>WITH CHECKSUMS</strong> or without them. When the workflow is complete, I recommend you use the following command: <strong><code>RESTORE VERIFYONLY</code></strong>. This command enables you to check the recoverability of backup files.  </p>
<p>To access the data, you can restore records from a backup to a different database. With Azure Automation scripts on backups, you can accelerate the restoration process, thus minimizing downtime and increasing the overall resilience of your Azure infrastructure. </p>
<p>You need to follow only a few steps to restore an Azure SQL database to a required recovery point from a backup. Still, keep in mind that your subscription can define the available retention period which can vary from 7 to 35 days. A native tool for backup restoration to SQL servers is Server Management Studio.</p>
<h2 id="heading-to-conclude">To Conclude</h2>
<p>The critical nature of Azure SQL database data makes Azure SQL backups obligatory for any organization that uses this Microsoft solution. In this guide, we reviewed the process of creating SQL Azure database backup using native Microsoft tools. </p>
<p>These tools provide data backup, backup verification, and recovery functionality along with some automation. </p>
<p>You can also implement a specialized all-in-one data protection solution, such as <a target="_blank" href="https://www.nakivo.com/backup-to-azure-blob/">NAKIVO</a>, the company where I work. It can help you make your data backup workflows more efficient.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ ACID Databases – Atomicity, Consistency, Isolation & Durability Explained ]]>
                </title>
                <description>
                    <![CDATA[ ACID stands for Atomicity, Consistency, Isolation and Durability. These are four key properties that most database management systems (DBMS) offer as guarantees when handling transactions. Most popular DBMS like MySQL, PostgresSQL and Oracle have ACI... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/acid-databases-explained/</link>
                <guid isPermaLink="false">66d45e01246e57ac83a2c725</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Adetunji ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jan 2024 17:45:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/cover-fcc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>ACID stands for Atomicity, Consistency, Isolation and Durability. These are four key properties that most database management systems (DBMS) offer as guarantees when handling transactions.</p>
<p>Most popular DBMS like <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/mysql-acid.html">MySQL</a>, <a target="_blank" href="https://www.postgresql.org/about/">PostgresSQL</a> and <a target="_blank" href="https://docs.oracle.com/cd/F51125_01/docs.85/SDS%20PI/acid-compliant-transactions.html#GUID-ECB79D66-46DE-4F48-93DC-8677E7BB44EF">Oracle</a> have ACID guarantees out of the box. Others have partial ACID guarantees like <a target="_blank" href="https://www.oreilly.com/library/view/redis-cookbook/9781449311353/ch01.html#:~:text=Redis%20provides%20partial%20ACID%20compliance,also%20be%20a%20key%20factor.">Redis</a>, DynamoDB, and Cassandra. The trend, however, seems to be that more and more DBMS are offering ACID compliance.</p>
<p>It is important to note that while a lot of DBMS may say they are ACID compliant, the implementation of this compliance can vary.</p>
<p>So, for example, if isolation is a key property that you need for an application you are building, you need to understand how exactly your chosen DBMS implements isolation.</p>
<p>This article will explain what transactions are, and go through, in detail, what atomicity, consistency, isolation and durability mean, using analogies and real world examples.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-are-transactions">What are Transactions?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-atomicity-mean">What Does Atomicity Mean?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-consistency-mean">What Does Consistency Mean?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-isolation-mean">What Does Isolation Mean?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-does-durability-mean">What Does Durability Mean?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-bringing-it-together">Bringing it Together</a></p>
</li>
</ol>
<h2 id="heading-what-are-transactions">What are Transactions?</h2>
<p>Lots of things can go wrong when using a database:</p>
<ul>
<li><p>the database hardware or software can fail</p>
</li>
<li><p>the application calling the database can fail mid-operation</p>
</li>
<li><p>the network can be flooded with more traffic can it can handle (rendering it inoperable)</p>
</li>
<li><p>several clients can make writes at the same time that overwrite the other’s changes</p>
</li>
<li><p>clients can read phantom data that should not be in the database</p>
</li>
</ul>
<p>And so on – this is in no way an exhaustive list of things that can go wrong.</p>
<p>Since things can fail in more ways than we can possibly anticipate, trying to prevent every possible failure can become unnecessarily expensive and complicated. Instead, it is better to design a system that can continue to operate in spite of a failure. Transactions allow us to do this.</p>
<p>Transactions serve a single purpose: they make sure a system is <a target="_blank" href="https://lightcloud.substack.com/i/59017006/fault-tolerance"><strong>fault tolerant</strong></a><strong>.</strong> If a failure in a system occurs, can the system continue to operate without complete catastrophe? Phrased differently, can the system tolerate faults? An answer of ‘yes’ to this question means that such a system is fault tolerant.</p>
<p>So, what exactly is a transaction?</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718d52b8-c016-4746-a1eb-73b6aac6d5fa_636x960.png" alt="Image" width="636" height="960" loading="lazy"></p>
<p><em>Not this kind of transaction</em></p>
<p>A transaction is an <a target="_blank" href="https://lightcloud.substack.com/p/cloud-computing-abstractions-explained">abstraction</a>. It is a collection of operations (reads and writes) that are treated as a single logical operation.</p>
<p>Imagine you want to buy a single book from an online store, say amazon.com. The steps below show a simplified view of what needs to happen:</p>
<ol>
<li><p>First, you select the book, which adds the item to your basket.</p>
</li>
<li><p>The inventory quantity of the book is checked to ensure it is valid (that is, the inventory value for the title you are buying needs to be greater than 0).</p>
</li>
<li><p>You click ‘buy’, which updates Amazon’s inventory for the book and decreases it by 1 (since you are buying a single book).</p>
</li>
<li><p>Also, your bank account balance is updated to account for the cost of the book.</p>
</li>
</ol>
<p>A transaction ensures that all operations related to the purchase are treated as a single operation. If any part of the transaction fails, the entire transaction is rolled back, leaving the database in a state as if the customer had never attempted the purchase, thus maintaining the integrity of the data.</p>
<p>The transaction is committed when all the operations within the transaction are successfully completed and their results are permanently recorded. This permanence is typically achieved by writing the changes to the database's storage, which could be on disk for traditional databases or in memory for in-memory databases like Redis.</p>
<p>By treating all of these different operations as a single logical operation, the database is able to offer some guarantees as to how it can be fault tolerant. These guarantees are <strong>atomicity</strong>, <strong>consistency</strong>, <strong>isolation</strong> and <strong>durability</strong>.</p>
<h2 id="heading-what-does-atomicity-mean">What Does Atomicity Mean?</h2>
<p>Atomicity simply means that all queries in a transaction must succeed for the transaction to succeed. If one query fails, the entire transaction fails.</p>
<h3 id="heading-an-atomic-restaurant">An Atomic Restaurant</h3>
<p>Imagine using a self-service machine at a fast-food restaurant. The transaction in this case is ordering food, and consists of two separate operations:</p>
<ol>
<li><p>Select food</p>
</li>
<li><p>Make payment</p>
</li>
</ol>
<p>Both of these must succeed for the transaction to succeed. If either fails, the transaction fails.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52901d6-a9e0-43a7-a198-d56ca2a82219_544x886.png" alt="Image" width="544" height="886" loading="lazy"></p>
<p><em>Customer making an order in an "atomic" restaurant</em></p>
<p>You select your burger, fries, and a drink from the touchscreen menu. The machine prompts you to pay, and only after your payment is processed successfully, it sends your order to the kitchen. Moments later, your entire order is ready, and you pick it up from the counter.</p>
<p>This is an atomic operation: the transaction (ordering food) is either entirely completed (if you select your food item and make a payment) or not completed at all.</p>
<p>Either part of the transaction failing means the entire transaction will fail. If your payment fails, the machine won't process any part of the order, so the transaction fails. If you make a payment without selecting a food item, the transaction also fails, as there is nothing for the kitchen to prepare.</p>
<h3 id="heading-a-non-atomic-restaurant">A Non-Atomic Restaurant</h3>
<p>Now consider the alternative, a traditional sit-down restaurant where you order several dishes. As each dish is prepared, it is brought to your table.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F045c9ec7-dbb9-45b7-ad4d-357f7b7cc37c_888x1026.png" alt="Image" width="888" height="1026" loading="lazy"></p>
<p><em>customer making an order in a "non-atomic" restaurant</em></p>
<p>Again, the transaction is ordering food, and consists of two separate operations:</p>
<ol>
<li><p>Select food</p>
</li>
<li><p>Make payment</p>
</li>
</ol>
<p>In this non-atomic restaurant, failure to make a payment does not stop the transaction from completing, since you pay after you have finished your meal. Partial failures do not cause a transaction to fail.</p>
<p>This creates a risk for the restaurant. Customers that choose to dine and dash can order food to their heart’s delight and then simply leave without paying, causing a financial loss for the restaurant.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4136ceee-82b9-4cf0-b0de-5a0af3f1aa71_2218x1278.png" alt="Image" width="1456" height="839" loading="lazy"></p>
<p><em>non-atomic restaurants are at risk of customers doing a dine and dash</em></p>
<h3 id="heading-atomic-transactions">Atomic Transactions</h3>
<p>If several SQL queries are grouped together in a transaction, atomicity is a guarantee that, should any of the queries fail for any reason (hardware, application or networking problems) then the transaction is aborted and the database returns to its previous state, as if nothing had happened.</p>
<p>Without atomicity, if a failure occurs while some queries are running, it is difficult to know which queries have been committed (that is, completed) and which have not. Running the queries again after a failure can compound the problem, since you risk introducing incorrect data to the database by re-running queries that previously succeeded.</p>
<p>Atomic transactions prevent such uncertainty, since you know that if the previous transaction failed, it failed in its entirety, and you can simply retry without worrying about introducing inconsistent data.</p>
<h2 id="heading-what-does-consistency-mean">What Does Consistency Mean?</h2>
<p>Consistency can mean different things in cloud/software engineering, depending on the context. In the case of ACID, the “C” was most likely added to make the acronym work.</p>
<p>Consistency in the context of ACID means <em>consistency in data</em>, which is defined by the creator of the database. The technical term for consistency in data is called referential integrity. Referential integrity is a method of ensuring that relationships between tables remain consistent. It's usually enforced through the use of foreign keys.</p>
<p>To understand referential integrity, consider the following.</p>
<p>Imagine a library system with two types of cards: a book card and a borrower's card.</p>
<ul>
<li><p>The book card lists all the books available in the library.</p>
</li>
<li><p>The borrower's card tracks which books are borrowed by which members.</p>
</li>
</ul>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82ea7c95-f55f-4cb6-86ea-47c11399b5c7_2324x1316.png" alt="Image" width="1456" height="824" loading="lazy"></p>
<p><em>A book card and borrower card for a library</em></p>
<p>The rule of the library is that a book can only be listed on a borrower's card if it exists on a book card. This is referential integrity. If someone tries to list a book on a borrower's card that isn't on the book card (that is a book that doesn’t exist in the library), the system will not allow it.</p>
<p>While atomicity, isolation and durability are properties intrinsic to the database itself, consistency in data, or referential integrity, is not a property intrinsic to the database.</p>
<p>Consistency is defined by the creator of the database. The application calling the database relies on the atomicity and isolation properties of the database to maintain that consistency.</p>
<h2 id="heading-what-does-isolation-mean">What Does Isolation Mean?</h2>
<p>Isolation is a guarantee that concurrently running transactions should not interfere with each other. Concurrency here refers to two or more transactions trying to modify or read the same database record(s) at the same time.</p>
<p>There are three levels of transaction isolation. I'll just explain the two main ones below, arranged in order from the least strict to most strict.</p>
<h3 id="heading-read-committed">Read Committed</h3>
<p>This gives two guarantees. It prevents dirty reads and dirty writes.</p>
<p><strong>No Dirty Reads</strong>: Reading data from another transaction that has not yet been committed is called a dirty read. With the read committed isolation level, you will only see data that has been committed by another transaction.</p>
<p><strong>No Dirty Writes</strong>: Overwriting data that has already been written by another transaction but not yet committed is called a dirty write.</p>
<p>To understand how read committed isolation works, consider the following example.</p>
<p>Imagine a fast-food restaurant with only one last special burger available, and two hungry customers, Marie and Marko, are trying to buy it simultaneously.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec0fd185-63c9-4821-bcac-b0140f2f4183_2360x1322.png" alt="Image" width="1456" height="816" loading="lazy"></p>
<p><em>Two customers ordering a burger at the same time</em></p>
<ol>
<li><p>Marie checks the availability of burgers and sees the last one available. Unknown to her, Marko’s order is being processed but hasn't been finalised in the system, as he has not paid. Since his order has not yet been finalised, Marie is not aware that his order conflicts with her own. This is similar to a transaction reading the most recently committed data, where it does not see uncommitted changes (like Marko's pending order).</p>
</li>
<li><p>Marie places an order based on this incomplete information, thinking a burger is available.</p>
</li>
<li><p>Once Marko pays, the system updates to show that there are no burgers left. This is similar to a transaction being committed</p>
</li>
<li><p>Marie’s order will have to be aborted since there are no burgers left.</p>
</li>
</ol>
<p>The key point here is step #3. What if Marko’s payment failed at this stage? Then the transaction will not be committed and there would still be a burger available for Marie.</p>
<p>In this example, read committed isolation ensures that Marie is not prematurely excluded from buying the burger just because someone else said they wanted it. Only committed transactions can be read. Therefore, the burger is available to be ordered as long as no one has paid for it.</p>
<h3 id="heading-repeatable-read">Repeatable Read</h3>
<p>The repeatable read is a more strict isolation level, in that it has the same guarantees as read committed isolation – plus it guarantees that reads are repeatable.</p>
<p>A repeatable read guarantees that if a transaction reads a row of data, any subsequent reads of that same row of data within the same transaction will yield the same result, regardless of changes made by other transactions. This consistency is maintained throughout the duration of the transaction.</p>
<p>When a transaction reads the same data twice, but sees a different value in each read because a committed transaction has updated the value between the two reads, this is called a fuzzy read. The repeatable read isolation level prevents fuzzy reads.</p>
<p>Fuzzy reads are neither inherently good nor bad. It all depends on what you are trying to achieve.</p>
<p>Fuzzy reads are bad for long-running, read-only transactions, since new writes are likely to occur during the transaction and this can cause inconsistencies in the data. Examples of long running, read-only transactions are a database backup and analytical queries typically used in a data warehouse.</p>
<p>Repeatable reads are usually implemented by the DBMS by reading from a snapshot of the database which remains unchanged for the duration of the transaction, thereby ignoring any new committed writes in that period.</p>
<h2 id="heading-what-does-durability-mean">What Does Durability Mean?</h2>
<p>Durability is a guarantee that changes made by a committed transaction must not be lost. All committed transactions must be persisted on durable, non-volatile storage, that is on disk. This ensures that any committed transactions are protected even if the database crashes.</p>
<p>Naturally, durability cannot protect against destruction of the disk which stores the data. Additional redundancy can be added by having backups of your database stored separately from the original.</p>
<h2 id="heading-bringing-it-together">Bringing it Together</h2>
<p>ACID (Atomicity, Consistency, Isolation, and Durability) provides a set of guarantees when working with a DBMS. While most relational DBMS are ACID compliant, the implementation of this compliance can vary.</p>
<p>Atomicity ensures that all parts of a transaction are completed or none at all. Partial failures are not allowed.</p>
<p>Consistency, or referential integrity, ensures that data remains accurate and reliable, adhering to predefined rules. Unlike the other priorities, consistency is not intrinsic to the DBMS itself. Instead, the application calling the database relies on the atomicity and isolation properties of the database to maintain consistency.</p>
<p>Isolation is a guarantee that concurrently running transactions should not interfere with each other. This is arguably the most important property because a DBMS can often have different default isolation levels, which may need to be changed based on what is needed for your application.</p>
<p>Finally, durability is a guarantee that changes made by a committed transaction must not be lost.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The SQL Handbook – A Free Course for Web Developers ]]>
                </title>
                <description>
                    <![CDATA[ SQL is everywhere these days. Whether you're learning backend development, data engineering, DevOps, or data science, SQL is a skill you'll want in your toolbelt. This a free and open text-based handbook. If you want to get started, just scroll down ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-beginners-guide-to-sql/</link>
                <guid isPermaLink="false">66b9e9e18ff373c48b152943</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lane Wagner ]]>
                </dc:creator>
                <pubDate>Tue, 05 Sep 2023 13:57:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/The-SQL-Handbook-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>SQL is everywhere these days. Whether you're <a target="_blank" href="https://www.boot.dev/">learning backend development</a>, data engineering, DevOps, or data science, SQL is a skill you'll want in your toolbelt.</p>
<p>This a free and open text-based handbook. If you want to get started, just scroll down and start reading. That said, there are two other options for following along:</p>
<ol>
<li>Try the interactive version of this <a target="_blank" href="https://boot.dev/learn/learn-gsql">SQL course</a> on <a target="_blank" href="https://boot.dev/">Boot.dev</a>, complete with coding challenges and projects</li>
<li>Watch the video walkthrough of this course on FreeCodeCamp's YouTube channel (embedded below):</li>
</ol>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/KBDSJU3cGkc" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-chapter-1-introduction">Chapter 1: Introduction</a></li>
<li><a class="post-section-overview" href="#heading-chapter-2-sql-tables">Chapter 2: SQL Tables</a></li>
<li><a class="post-section-overview" href="#heading-chapter-3-constraints">Chapter 3: Constraints</a></li>
<li><a class="post-section-overview" href="#heading-chapter-4-crud-operations-in-sql">Chapter 4: CRUD Operations</a></li>
<li><a class="post-section-overview" href="#heading-chapter-5-basic-sql-queries">Chapter 5: Basic SQL Queries</a></li>
<li><a class="post-section-overview" href="#heading-chapter-6-how-to-structure-return-data-in-sql">Chapter 6: How to Structure Return Data in SQL</a></li>
<li><a class="post-section-overview" href="#heading-chapter-7-how-to-perform-aggregations-in-sql">Chapter 7: How to Perform Aggregations in SQL</a></li>
<li><a class="post-section-overview" href="#heading-chapter-8-sql-subqueries">Chapter 8: SQL Subqueries</a></li>
<li><a class="post-section-overview" href="#heading-chapter-9-database-normalization">Chapter 9: Database Normalization</a></li>
<li><a class="post-section-overview" href="#heading-chapter-10-how-to-join-tables-in-sql">Chapter 10: How to Join Tables in SQL</a></li>
<li><a class="post-section-overview" href="#heading-chapter-11-database-performance">Chapter 11: Database Performance</a></li>
</ul>
<h2 id="heading-chapter-1-introduction">Chapter 1: Introduction</h2>
<p>Structured Query Language, or <a target="_blank" href="https://www.freecodecamp.org/news/what-is-sql-database-definition-for-beginners/">SQL</a>, is the primary programming language used to manage and interact with <a target="_blank" href="https://cloud.google.com/learn/what-is-a-relational-database">relational databases</a>. SQL can perform various operations such as creating, updating, reading, and deleting records within a database.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/pYKirBUnr-8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-what-is-a-sql-select-statement">What is a SQL Select Statement?</h3>
<p>Let's write our own SQL statement from scratch. A <code>SELECT</code> statement is the most common operation in SQL – often called a "query". <code>SELECT</code> retrieves data from one or more tables. Standard <code>SELECT</code> statements do <em>not</em> alter the state of the database.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> <span class="hljs-keyword">from</span> <span class="hljs-keyword">users</span>;
</code></pre>
<h4 id="heading-how-to-select-a-single-field">How to select a single field</h4>
<p>A <code>SELECT</code> statement begins with the keyword <code>SELECT</code> followed by the fields you want to retrieve.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span> <span class="hljs-keyword">from</span> <span class="hljs-keyword">users</span>;
</code></pre>
<h4 id="heading-how-to-select-multiple-fields">How to select multiple fields</h4>
<p>If you want to select more than one field, you can specify multiple fields separated by commas like this:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span> <span class="hljs-keyword">from</span> <span class="hljs-keyword">users</span>;
</code></pre>
<h4 id="heading-how-to-select-all-fields">How to select all fields</h4>
<p>If you want to select <em>every</em> field in a record, you can use the shorthand <code>*</code> syntax.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">from</span> <span class="hljs-keyword">users</span>;
</code></pre>
<p>After specifying fields, you need to indicate which table you want to pull the records from using the <code>from</code> statement followed by the name of the table. </p>
<p>We'll talk more about tables later, but for now, you can think about them like structs or objects. For example, the <code>users</code> table might have 3 fields:</p>
<ul>
<li><code>id</code></li>
<li><code>name</code></li>
<li><code>balance</code></li>
</ul>
<p>And finally, <em>all</em> statements end with a semi-colon <code>;</code>.</p>
<h3 id="heading-which-databases-use-sql">Which Databases Use SQL?</h3>
<p>SQL is just a query language. You typically use it to interact with a specific database technology. For example: </p>
<ul>
<li><a target="_blank" href="https://www.sqlite.org/index.html">SQLite</a></li>
<li><a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a></li>
<li><a target="_blank" href="https://www.mysql.com/">MySQL</a></li>
<li><a target="_blank" href="https://www.cockroachlabs.com/">CockroachDB</a></li>
<li><a target="_blank" href="https://www.oracle.com/database/">Oracle</a></li>
</ul>
<p>And others.</p>
<p>Although many different databases use the SQL <em>language</em>, most of them will have their own <em>dialect</em>. It's critical to understand that not all databases are created equal. Just because one SQL-compatible database does things a certain way, doesn't mean every SQL-compatible database will follow those exact same patterns.</p>
<h4 id="heading-were-using-sqlite">We're using SQLite</h4>
<p>In this course, we'll be using <a target="_blank" href="https://www.sqlite.org/index.html">SQLite</a> specifically. SQLite is great for embedded projects, web browsers, and toy projects. It's lightweight, but has limited functionality compared to the likes of PostgreSQL or MySQL – two of the more common production SQL technologies.</p>
<p>And I'll make sure to point out to you whenever some functionality we're working with is unique to SQLite.</p>
<h2 id="heading-nosql-vs-sql">NoSQL vs SQL</h2>
<p>When talking about SQL databases, we also have to mention the elephant in the room: <a target="_blank" href="https://en.wikipedia.org/wiki/NoSQL">NoSQL</a>.</p>
<p>To put it simply, a NoSQL database is a database that does not use SQL (Structured Query Language). Each NoSQL typically has its own way of writing and executing queries. For example, <a target="_blank" href="https://www.mongodb.com/">MongoDB</a> uses MQL (MongoDB Query Language) and <a target="_blank" href="https://www.elastic.co/">ElasticSearch</a> simply has a JSON API.</p>
<p>While most relational databases are fairly similar, NoSQL databases tend to be fairly unique and are used for more niche purposes. Some of the main differences between a SQL and NoSQL database are:</p>
<ol>
<li>NoSQL databases are usually non-relational, SQL databases are usually <a target="_blank" href="https://cloud.google.com/learn/what-is-a-relational-database">relational</a> (we'll talk more about what this means later).</li>
<li>SQL databases usually have a defined schema, NoSQL databases usually have dynamic schema.</li>
<li>SQL databases are table-based, NoSQL databases have a variety of different storage methods, such as document, key-value, graph, wide-column, and more.</li>
</ol>
<h3 id="heading-types-of-nosql-databases">Types of NoSQL databases</h3>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Document-oriented_database">Document Database</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database">Key-Value Store</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Wide-column_store">Wide-Column</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Graph_database">Graph</a></li>
</ul>
<p>A few of the most popular NoSQL databases are:</p>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/MongoDB">MongoDB</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Apache_Cassandra">Cassandra</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Apache_CouchDB">CouchDB</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Amazon_DynamoDB">DynamoDB</a></li>
<li><a target="_blank" href="https://www.elastic.co/">ElasticSearch</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/NovjCrDFlXk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-comparing-sql-databases">Comparing SQL Databases</h3>
<p>Let's dive deeper and talk about some of the popular SQL Databases and what makes them different from one another. Some of the most popular SQL Databases right now are:</p>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/PostgreSQL">PostgreSQL</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/MySQL">MySQL</a></li>
<li><a target="_blank" href="https://db-engines.com/en/system/Microsoft+SQL+Server">Microsoft SQL Server</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/SQLite">SQLite</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/List_of_relational_database_management_systems">And many others</a></li>
</ul>
<p>Source: <a target="_blank" href="https://db-engines.com/en/ranking">db-engines.com</a></p>
<p>While all of these Databases use SQL, each database defines specific rules, practices, and strategies that separate them from their competitors. </p>
<h4 id="heading-sqlite-vs-postgresql">SQLite vs PostgreSQL</h4>
<p>Personally, SQLite and PostgreSQL are my favorites from the list above. Postgres is a very powerful, open-source, production-ready SQL database. SQLite is a lightweight, embeddable, open-source database. I usually choose one of these technologies if I'm doing SQL work.</p>
<p>SQLite is a serverless database management system (DBMS) that has the ability to run within applications, whereas PostgreSQL uses a Client-Server model and requires a server to be installed and listening on a network, similar to an HTTP server.</p>
<p>See a full <a target="_blank" href="https://db-engines.com/en/system/PostgreSQL%3BSQLite">comparison here</a>.</p>
<p>Again, in this course we will be working with SQLite, a lightweight and simple database. For most <a target="_blank" href="https://blog.boot.dev/backend/do-backend-devs-need-sql/">backend</a> web servers, PostgreSQL is a more production-ready option, but SQLite is great for learning and for small systems.</p>
<h2 id="heading-chapter-2-sql-tables">Chapter 2: SQL Tables</h2>
<p>The <code>CREATE TABLE</code> statement is used to create a new table in a database.</p>
<h3 id="heading-how-to-use-the-create-table-statement">How to use the <code>CREATE TABLE</code> statement</h3>
<p>To create a table, use the <code>CREATE TABLE</code> statement followed by the name of the table and the fields you want in the table.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees (<span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span>, <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span>, age <span class="hljs-built_in">INTEGER</span>, is_manager <span class="hljs-built_in">BOOLEAN</span>, salary <span class="hljs-built_in">INTEGER</span>);
</code></pre>
<p>Each field name is followed by its datatype. We'll get to data types in a minute.</p>
<p>It's also acceptable and common to break up the <code>CREATE TABLE</code> statement with some whitespace like this:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span>,
    age <span class="hljs-built_in">INTEGER</span>,
    is_manager <span class="hljs-built_in">BOOLEAN</span>,
    salary <span class="hljs-built_in">INTEGER</span>
);
</code></pre>
<h3 id="heading-how-to-alter-tables">How to Alter Tables</h3>
<p>We often need to alter our database schema without deleting it and re-creating it. Imagine if Twitter deleted its database each time it needed to add a feature, that would be a disaster! Your account and all your tweets would be wiped out on a daily basis.</p>
<p>Instead, we can use use the <code>ALTER TABLE</code> statement to make changes in place without deleting any data.</p>
<h4 id="heading-how-to-use-alter-table">How to use <code>ALTER TABLE</code></h4>
<p>With SQLite an <code>ALTER TABLE</code> statement allows you to:</p>
<ol>
<li>Rename a table or column, which you can do like this:</li>
</ol>
<pre><code class="lang-SQL"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> employees
<span class="hljs-keyword">RENAME</span> <span class="hljs-keyword">TO</span> contractors;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> contractors
<span class="hljs-keyword">RENAME</span> <span class="hljs-keyword">COLUMN</span> salary <span class="hljs-keyword">TO</span> invoice;
</code></pre>
<ol start="2">
<li>ADD or DROP a column, which you can do like this:</li>
</ol>
<pre><code class="lang-SQL"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> contractors
<span class="hljs-keyword">ADD</span> <span class="hljs-keyword">COLUMN</span> job_title <span class="hljs-built_in">TEXT</span>;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> contractors
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">COLUMN</span> is_manager;
</code></pre>
<h3 id="heading-intro-to-migrations">Intro to Migrations</h3>
<p>A database <a target="_blank" href="https://en.wikipedia.org/wiki/Schema_migration">migration</a> is a set of changes to a relational database. In fact, the <code>ALTER TABLE</code> statements we did in the last exercise were examples of migrations.</p>
<p>Migrations are helpful when transitioning from one state to another, fixing mistakes, or adapting a database to changes. </p>
<p>Good migrations are small, incremental and ideally reversible changes to a database. As you can imagine, when working with large databases, making changes can be scary. We have to be careful when writing database migrations so that we don't break any systems that depend on the old database schema.</p>
<h4 id="heading-example-of-a-bad-migration">Example of a bad migration</h4>
<p>If a backend server periodically runs a query like <code>SELECT * FROM people</code>, and we execute a database migration that alters the table name from <code>people</code> to <code>users</code> <em>without updating the code</em>, the application will break. It will try to grab data from a table that no longer exists.</p>
<p>A simple solution to this problem would be to deploy new code that uses a new query:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>;
</code></pre>
<p>And we would deploy that code to production immediately following the migration.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/iHIGUpEVN6Y" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-sql-data-types">SQL Data Types</h3>
<p>SQL as a language can support many different data types. But the datatypes that your database management system (<a target="_blank" href="https://en.wikipedia.org/wiki/Database#:~:text=A%20database%20management%20system%20(DBMS)">DBMS</a>) supports will vary depending on the specific database you're using.</p>
<p>SQLite only supports the most basic types, and we're using SQLite in this course.</p>
<h4 id="heading-sqlite-data-types">SQLite Data Types</h4>
<p>Let's go over the <a target="_blank" href="https://www.sqlite.org/datatype3.html">data types supported by SQLite:</a> and how they are stored.</p>
<ol>
<li><code>NULL</code> - Null value.</li>
<li><code>INTEGER</code> - A signed integer stored in 0,1,2,3,4,6, or 8 bytes.</li>
<li><code>REAL</code> - Floating point value stored as an 64-bit <a target="_blank" href="https://en.wikipedia.org/wiki/IEEE_754">IEEE floating point number</a>.</li>
<li><code>TEXT</code> - Text string stored using database encoding such as <a target="_blank" href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a></li>
<li><code>BLOB</code> - Short for <a target="_blank" href="https://en.wikipedia.org/wiki/Binary_large_object">Binary large object</a> and typically used for images, audio or other multimedia.</li>
</ol>
<p>For example:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span>,
    age <span class="hljs-built_in">INTEGER</span>,
    is_manager <span class="hljs-built_in">BOOLEAN</span>,
    salary <span class="hljs-built_in">INTEGER</span>
);
</code></pre>
<h4 id="heading-boolean-values">Boolean values</h4>
<p>It's important to note that SQLite does not have a separate <code>BOOLEAN</code> storage class. Instead, boolean values are stored as integers:</p>
<ul>
<li><code>0</code> = <code>false</code></li>
<li><code>1</code> = <code>true</code></li>
</ul>
<p>It's not actually all that weird – boolean values are just binary bits after all!</p>
<p>SQLite will still let you write your queries using <code>boolean</code> expressions and <code>true</code>/<code>false</code> keywords, but it will convert the booleans to integers under-the-hood.</p>
<h2 id="heading-chapter-3-constraints">Chapter 3: Constraints</h2>
<p>A <code>constraint</code> is a rule we create on a database that enforces some specific behavior. For example, setting a <code>NOT NULL</code> constraint on a column ensures that the column will not accept <code>NULL</code> values.</p>
<p>If we try to insert a <code>NULL</code> value into a column with the <code>NOT NULL</code> constraint, the insert will fail with an error message. Constraints are extremely useful when we need to ensure that certain kinds of data exist within our database. </p>
<h4 id="heading-not-null-constraint">NOT NULL constraint</h4>
<p>The <code>NOT NULL</code> constraint can be added directly to the <code>CREATE TABLE</code> statement.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">UNIQUE</span>,
    title <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);
</code></pre>
<h4 id="heading-sqlite-limitation">SQLite limitation</h4>
<p>In other dialects of SQL you can <code>ADD CONSTRAINT</code> within an <code>ALTER TABLE</code> statement. SQLite does not support this feature, so when we create our tables we need to make sure we specify all the constraints we want. </p>
<p>Here's a <a target="_blank" href="https://www.sqlite.org/omitted.html">list of SQL Features</a> SQLite does not implement in case you're curious.</p>
<h3 id="heading-primary-key-constraints">Primary Key Constraints</h3>
<p>A <em>key</em> defines and protects relationships between tables. A <a target="_blank" href="https://en.wikipedia.org/wiki/Primary_key"><code>primary key</code></a> is a special column that uniquely identifies records within a table. Each table can have one, and only one primary key.</p>
<h4 id="heading-your-primary-key-will-almost-always-be-the-id-column">Your primary key will almost always be the "id" column</h4>
<p>It's very common to have a column named <code>id</code> on each table in a database, and that <code>id</code> is the primary key for that table. No two rows in that table can share an <code>id</code>.</p>
<p>A <code>PRIMARY KEY</code> constraint can be explicitly specified on a column to ensure uniqueness, rejecting any inserts where you attempt to create a duplicate ID.</p>
<h3 id="heading-foreign-key-constraints">Foreign Key Constraints</h3>
<p>Foreign keys are what makes relational databases relational! Foreign keys define the relationships <em>between</em> tables. Simply put, a <code>FOREIGN KEY</code> is a field in one table that references another table's <code>PRIMARY KEY</code>.</p>
<h4 id="heading-creating-a-foreign-key-in-sqlite">Creating a Foreign Key in SQLite</h4>
<p>Creating a <code>FOREIGN KEY</code> in SQLite happens at table creation! After we define the table fields and constraints we add an additional <code>CONSTRAINT</code> where we define the <code>FOREIGN KEY</code> and its <code>REFERENCES</code>.</p>
<p>Here's an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> departments (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    department_name <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> employees (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INTEGER</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    department_id <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-keyword">CONSTRAINT</span> fk_departments
    <span class="hljs-keyword">FOREIGN</span> <span class="hljs-keyword">KEY</span> (department_id)
    <span class="hljs-keyword">REFERENCES</span> departments(<span class="hljs-keyword">id</span>)
);
</code></pre>
<p>In this example, an <code>employee</code> has a <code>department_id</code>. The <code>department_id</code> must be the same as the <code>id</code> field of a record from the <code>departments</code> table.</p>
<h3 id="heading-schema">Schema</h3>
<p>We've used the word <em>schema</em> a few times now, let's talk about what that word means. A database's <a target="_blank" href="https://www.ibm.com/cloud/learn/database-schema">schema</a> describes how data is organized within it.</p>
<p>Data types, table names, field names, constraints, and the relationships between all of those entities are part of a database's <em>schema</em>.</p>
<h4 id="heading-there-is-no-perfect-way-to-architect-a-database-schema">There is no perfect way to architect a database schema</h4>
<p>When designing a database schema there typically isn't a "correct" solution. We do our best to choose a sane set of tables, fields, constraints, etc that will accomplish our project's goals. Like many things in programming, different schema designs come with different tradeoffs.</p>
<h4 id="heading-how-do-we-decide-on-a-sane-schema-architecture">How do we decide on a sane schema architecture?</h4>
<p>One very important decision that needs to be made is to decide which table will store a user's balance! As you can imagine, ensuring our data is accurate when dealing with money is <em>super</em> important. We want to be able to:</p>
<ul>
<li>Keep track of a user's current balance</li>
<li>See the historical balance at any point in the past</li>
<li>See a log of which transactions changed the balance over time</li>
</ul>
<p>There are many ways to approach this problem. For our first attempt, let's try the simplest schema that fulfills our project's needs. </p>
<h2 id="heading-chapter-4-crud-operations-in-sql">Chapter 4: CRUD Operations in SQL</h2>
<h3 id="heading-what-is-crud">What is CRUD?</h3>
<p>CRUD is an acronym that stands for <code>CREATE</code>, <code>READ</code>, <code>UPDATE</code>, and <code>DELETE</code>. These four operations are the bread and butter of nearly every database you will create. </p>
<h4 id="heading-http-and-crud">HTTP and CRUD</h4>
<p>The CRUD operations correlate nicely with the HTTP methods you may have already learned:</p>
<ul>
<li><code>HTTP POST</code> - <code>CREATE</code></li>
<li><code>HTTP GET</code> - <code>READ</code></li>
<li><code>HTTP PUT</code> - <code>UPDATE</code></li>
<li><code>HTTP DELETE</code> - <code>DELETE</code></li>
</ul>
<h3 id="heading-sql-insert-statement">SQL Insert Statement</h3>
<p>Tables are pretty useless without data in them. In SQL we can add records to a table using an <code>INSERT INTO</code> statement. When using an <code>INSERT</code> statement we must first specify the <code>table</code> we are inserting the record into, followed by the <code>fields</code> within that table we want to add <code>VALUES</code> to.</p>
<p>Here's an example of an <code>INSERT INTO</code> statement:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> employees(<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, title)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'Allan'</span>, <span class="hljs-string">'Engineer'</span>);
</code></pre>
<h3 id="heading-http-crud-database-lifecycle">HTTP CRUD Database lifecycle</h3>
<p>It's important to understand how data <em>flows</em> through a typical web application.</p>
<p><img src="https://i.imgur.com/hli3crD.png" alt="database flow" width="799" height="386" loading="lazy"></p>
<ol>
<li>The front-end processes some data from user input - maybe a form is submitted.</li>
<li>The front-end sends that data to the server through an HTTP request - maybe a <code>POST</code>.</li>
<li>The server makes a SQL query to it's database to create an associated record - Probably using an <code>INSERT</code> statement.</li>
<li>Once the server has processed that the database query was successful, it responds to the front-end with a status code! Hopefully a 200-level code (success)!</li>
</ol>
<h3 id="heading-manual-entry">Manual Entry</h3>
<p>Manually <code>INSERT</code>ing every single record in a database would be an <em>extremely</em> time-consuming task! Working with raw SQL as we are now is not super common when designing <a target="_blank" href="https://blog.boot.dev/backend/do-backend-devs-need-sql/">backend systems</a>.</p>
<p>When working with SQL within a software system, like a backend web application, you'll typically have access to a programming language such as <a target="_blank" href="https://boot.dev/learn/learn-golang">Go</a> or <a target="_blank" href="https://boot.dev/learn/learn-python">Python</a>. </p>
<p>For example, a backend server written in Go can use string concatenation to dynamically create SQL statements, and that's usually how it's done.</p>
<pre><code class="lang-go">sqlQuery := fmt.Sprintf(<span class="hljs-string">`
INSERT INTO users(name, age, country_code)
VALUES ('%s', %v, %s);
`</span>, user.Name, user.Age, user.CountryCode)
</code></pre>
<h4 id="heading-sql-injection">SQL Injection</h4>
<p>The example above is an oversimplification of what <em>really</em> happens when you access a database using Go code. In essence, it's correct. String interpolation is how production systems access databases. That said, it must be done <em>carefully</em> to not be a <a target="_blank" href="https://en.wikipedia.org/wiki/SQL_injection">security vulnerability</a>. We'll talk more about that later!</p>
<h3 id="heading-count">Count</h3>
<p>We can use a <code>SELECT</code> statement to get a count of the records within a table. This can be very useful when we need to know how many records there are, but we don't particularly care what's in them.</p>
<p>Here's an example in SQLite:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">count</span>(*) <span class="hljs-keyword">from</span> employees;
</code></pre>
<p>The <code>*</code> in this case refers to a column name. We don't care about the count of a specific column - we want to know the number of total records so we can use the wildcard (*).</p>
<h3 id="heading-http-crud-database-lifecycle-1">HTTP CRUD database lifecycle</h3>
<p>We talked about how a "create" operation flows through a web application. Let's talk about a "read".</p>
<p><img src="https://i.imgur.com/KTDQGy1.png" alt="read lifecycle" width="787" height="352" loading="lazy"></p>
<p>Let's talk through an example. Our product manager wants to show profile data on a user's settings page. Here's how we could engineer that feature request:</p>
<ol>
<li>First, the front-end webpage loads.</li>
<li>The front-end sends an HTTP <code>GET</code> request to a <code>/users</code> endpoint on the back-end server.</li>
<li>The server receives the request.</li>
<li>The server uses a <code>SELECT</code> statement to retrieve the user's record from the <code>users</code> table in the database.</li>
<li>The server converts the row of SQL data into a <code>JSON</code> object and sends it back to the front-end.</li>
</ol>
<h3 id="heading-where-clause">WHERE clause</h3>
<p>In order to keep learning about CRUD operations in SQL, we need to learn how to make the instructions we send to the database more specific. SQL accepts a <code>WHERE</code> statement within a query that allows us to be very specific with our instructions.</p>
<p>If we were unable to specify the specific record we wanted to <code>READ</code>, <code>UPDATE</code>, or <code>DELETE</code> making queries to a database would be very frustrating, and very inefficient.</p>
<h4 id="heading-using-a-where-clause">Using a WHERE clause</h4>
<p>Say we had over 9000 records in our <code>users</code> table. We often want to look at specific user data within that table without retrieving <em>all</em> the other records in the table. We can use a <code>SELECT</code> statement followed by a <code>WHERE</code> clause to specify which records to retrieve. The <code>SELECT</code> statement stays the same, we just add the <code>WHERE</code> clause to the end of the <code>SELECT</code>. </p>
<p>Here's an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> power_level &gt;= <span class="hljs-number">9000</span>;
</code></pre>
<p>This will select only the <code>name</code> field of any user within the <code>users</code> table <code>WHERE</code> the <code>power_level</code> field is greater than or equal to <code>9000</code>.</p>
<h3 id="heading-finding-null-values">Finding NULL values</h3>
<p>You can use a <code>WHERE</code> clause to filter values by whether or not they're <code>NULL</code>.</p>
<h4 id="heading-is-null">IS NULL</h4>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> first_name <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span>;
</code></pre>
<h4 id="heading-is-not-null">IS NOT NULL</h4>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> first_name <span class="hljs-keyword">IS</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>;
</code></pre>
<h3 id="heading-delete">DELETE</h3>
<p>When a user deletes their account on Twitter, or deletes a comment on a YouTube video, that data needs to be removed from its respective database.</p>
<h4 id="heading-delete-statement">DELETE statement</h4>
<p>A <code>DELETE</code> statement removes a record from a table that match the <code>WHERE</code> clause. As an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">from</span> employees
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">251</span>;
</code></pre>
<p>This <code>DELETE</code> statement removes all records from the <code>employees</code> table that have an id of <code>251</code>!</p>
<h3 id="heading-the-danger-of-deleting-data">The danger of deleting data</h3>
<p>Deleting data can be a dangerous operation. Once removed, data can be really hard if not impossible to restore! Let's talk about a couple of common ways back-end engineers protect against losing valuable customer data.</p>
<h4 id="heading-strategy-1-backups">Strategy 1 - Backups</h4>
<p>If you're using a cloud-service like GCP's <a target="_blank" href="https://cloud.google.com/sql">Cloud SQL</a> or AWS's <a target="_blank" href="https://aws.amazon.com/rds/">RDS</a> you should <em>always</em> turn on automated backups. They take an automatic snapshot of your entire database on some interval, and keep it around for some length of time.</p>
<p>For example, the Boot.dev database has a backup snapshot taken daily and we retain those backups for 30 days. If I ever accidentally run a query that deletes valuable data, I can restore it from the backup.</p>
<p><strong>You should have a backup strategy for production databases.</strong></p>
<h4 id="heading-strategy-2-soft-deletes">Strategy 2 - Soft deletes</h4>
<p>A "soft delete" is when you don't actually delete data from your database, but instead just "mark" the data as deleted. </p>
<p>For example, you might set a <code>deleted_at</code> date on the row you want to delete. Then, in your queries you ignore anything that has a <code>deleted_at</code> date set. The idea is that this allows your application to behave as if it's deleting data, but you can always go back and restore any data that's been removed.</p>
<p>You should probably only soft-delete if you have a specific reason to do so. Automated backups should be "good enough" for most applications that are just interested in protecting against developer mistakes.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/kCWHniEnQDM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-update-query-in-sql">Update query in SQL</h3>
<p>Whenever you update your profile picture or change your password online, you are changing the data in a field on a table in a database. Imagine if every time you accidentally messed up a Tweet on Twitter you had to delete the entire tweet and post a new one instead of just editing it...</p>
<p>...Well, that's a bad example.</p>
<h4 id="heading-update-statement">Update statement</h4>
<p>The <code>UPDATE</code> statement in SQL allows us to update the fields of a record. We can even update many records depending on how we write the statement.</p>
<p>An <code>UPDATE</code> statement specifies the table that needs to be updated, followed by the fields and their new values by using the <code>SET</code> keyword. Lastly a <code>WHERE</code> clause indicates the record(s) to update.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">UPDATE</span> employees
<span class="hljs-keyword">SET</span> job_title = <span class="hljs-string">'Backend Engineer'</span>, salary = <span class="hljs-number">150000</span>
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">251</span>;
</code></pre>
<h3 id="heading-object-relational-mapping-orms">Object-Relational Mapping (ORMs)</h3>
<p>An <a target="_blank" href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">Object-Relational Mapping</a> or an <em>ORM</em> for short, is a tool that allows you to perform CRUD operations on a database using a traditional programming language. These typically come in the form of a library or framework that you would use in your backend code.</p>
<p>The primary benefit an ORM provides is that it maps your database records to in-memory objects. For example, in Go we might have a struct that we use in our code:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID <span class="hljs-keyword">int</span>
    Name <span class="hljs-keyword">string</span>
    IsAdmin <span class="hljs-keyword">bool</span>
}
</code></pre>
<p>This struct definition conveniently represents a database table called <code>users</code>, and an instance of the struct represents a row in the table.</p>
<h4 id="heading-example-using-an-orm">Example: Using an ORM</h4>
<p>Using an ORM we might be able to write simple code like this:</p>
<pre><code class="lang-go">user := User{
    ID: <span class="hljs-number">10</span>,
    Name: <span class="hljs-string">"Lane"</span>,
    IsAdmin: <span class="hljs-literal">false</span>,
}

<span class="hljs-comment">// generates a SQL statement and runs it,</span>
<span class="hljs-comment">// creating a new record in the users table</span>
db.Create(user)
</code></pre>
<h4 id="heading-example-using-straight-sql">Example: Using straight SQL</h4>
<p>Using straight SQL we might have to do something a bit more manual:</p>
<pre><code class="lang-go">user := User{
    ID: <span class="hljs-number">10</span>,
    Name: <span class="hljs-string">"Lane"</span>,
    IsAdmin: <span class="hljs-literal">false</span>,
}

db.Exec(<span class="hljs-string">"INSERT INTO users (id, name, is_admin) VALUES (?, ?, ?);"</span>,
    user.ID, user.Name, user.IsAdmin)
</code></pre>
<h4 id="heading-should-you-use-an-orm">Should you use an ORM?</h4>
<p>That depends – an ORM typically trades simplicity for control.</p>
<p>Using straight SQL you can take full advantage of the power of the SQL language. Using an ORM, you're limited by whatever functionality the ORM has. </p>
<p>If you run into issues with a specific query, it can be harder to debug with an ORM because you have to dig through the framework's code and documentation to figure out how the underlying queries are being generated.</p>
<p>I recommend doing projects both ways so that you can learn about the tradeoffs. At the end of the day, when you're working on a team of developers, it will be a team decision.</p>
<h2 id="heading-chapter-5-basic-sql-queries">Chapter 5: Basic SQL Queries</h2>
<h3 id="heading-how-to-use-the-as-clause-in-sql">How to use the <code>AS</code> Clause in SQL</h3>
<p>Sometimes we need to structure the data we return from our queries in a specific way. An <code>AS</code> clause allows us to "alias" a piece of data in our query. The alias only exists for the duration of the query. </p>
<h4 id="heading-as-keyword"><code>AS</code> keyword</h4>
<p>The following queries return the same data:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> employee_id <span class="hljs-keyword">AS</span> <span class="hljs-keyword">id</span>, employee_name <span class="hljs-keyword">AS</span> <span class="hljs-keyword">name</span>
<span class="hljs-keyword">FROM</span> employees;
</code></pre>
<p>and:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> employee_id, employee_name
<span class="hljs-keyword">FROM</span> employees;
</code></pre>
<p>The difference is that the results from the aliased query would have column names <code>id</code> and <code>name</code> instead of <code>employee_id</code> and <code>employee_name</code>.</p>
<h3 id="heading-sql-functions">SQL Functions</h3>
<p>At the end of the day, SQL is a programming language, and it's one that supports functions. We can use functions and aliases to <em>calculate</em> new columns in a query. This is similar to how you might use formulas in Excel.</p>
<h4 id="heading-iif-function">IIF function</h4>
<p>In SQLite, the <code>IIF</code> function works like a <a target="_blank" href="https://book.pythontips.com/en/latest/ternary_operators.html">ternary</a>. For example:</p>
<pre><code class="lang-SQL">IIF(carA &gt; carB, "Car a is bigger", "Car b is bigger")
</code></pre>
<p>If <code>a</code> is greater than <code>b</code>, this statement evaluates to the string <code>"Car a is bigger"</code>. Otherwise, it evaluates to <code>"Car b is bigger"</code>.</p>
<p>Here's how we can use <code>IIF()</code> and a <code>directive</code> alias to add a new calculated column to our result set:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> quantity,
    <span class="hljs-keyword">IIF</span>(quantity &lt; <span class="hljs-number">10</span>, <span class="hljs-string">"Order more"</span>, <span class="hljs-string">"In Stock"</span>) <span class="hljs-keyword">AS</span> directive
    <span class="hljs-keyword">from</span> products
</code></pre>
<h3 id="heading-how-to-use-between-with-where">How to Use <code>BETWEEN</code> with <code>WHERE</code></h3>
<p>We can check if certain values are <code>between</code> two numbers using the <code>WHERE</code> clause in an intuitive way. The <code>WHERE</code> clause doesn't always have to be used to specify specific id's or values. We can also use it to help narrow down our result set. Here's an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> employee_name, salary
<span class="hljs-keyword">FROM</span> employees
<span class="hljs-keyword">WHERE</span> salary <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">30000</span> <span class="hljs-keyword">and</span> <span class="hljs-number">60000</span>;
</code></pre>
<p>This query returns all the employees <code>name</code> and <code>salary</code> fields for any rows where the <code>salary</code> is <code>BETWEEN</code> 30,000 and 60,000. We can also query results that are <code>NOT BETWEEN</code> two specified values. </p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, quantity
<span class="hljs-keyword">FROM</span> products
<span class="hljs-keyword">WHERE</span> quantity <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">20</span> <span class="hljs-keyword">and</span> <span class="hljs-number">100</span>;
</code></pre>
<p>This query returns all the product names where the quantity was not between <code>20</code> and <code>100</code>. We can use conditionals to make the results of our query as specific as we need them to be.</p>
<h3 id="heading-how-to-return-distinct-values">How to return distinct values</h3>
<p>Sometimes we want to retrieve records from a table without getting back any duplicates.</p>
<p>For example, we may want to know all the different companies our employees have worked at previously, but we don't want to see the same company multiple times in the report.</p>
<h4 id="heading-select-distinct"><code>SELECT DISTINCT</code></h4>
<p>SQL offers us the <code>DISTINCT</code> keyword that removes duplicate records from the resulting query.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">DISTINCT</span> previous_company
    <span class="hljs-keyword">FROM</span> employees;
</code></pre>
<p>This only returns one row for each unique <code>previous_company</code> value.</p>
<h3 id="heading-logical-operators">Logical Operators</h3>
<p>We often need to use multiple conditions to retrieve the exact information we want. We can begin to structure much more complex queries by using multiple conditions together to narrow down the search results of our query.</p>
<p>The logical <code>AND</code> operator can be used to narrow down our result sets even more.</p>
<h4 id="heading-and-operator"><code>AND</code> operator</h4>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, quantity, shipment_status
    <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> shipment_status = <span class="hljs-string">'pending'</span>
    <span class="hljs-keyword">AND</span> quantity <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-number">10</span>;
</code></pre>
<p>This only retrieves records where both the <code>shipment_status</code> is "pending" AND the <code>quantity</code> is between <code>0</code> and <code>10</code>.</p>
<h4 id="heading-equality-operators">Equality operators</h4>
<p>All of the following operators are supported in SQL. The <code>=</code> is the main one to watch out for, it's not <code>==</code> like in many other languages.</p>
<ul>
<li><code>=</code></li>
<li><code>&lt;</code></li>
<li><code>&gt;</code></li>
<li><code>&lt;=</code></li>
<li><code>&gt;=</code></li>
</ul>
<p>For example, in Python you might compare two values like this:</p>
<pre><code class="lang-py"><span class="hljs-keyword">if</span> name == <span class="hljs-string">"age"</span>
</code></pre>
<p>Whereas in SQL you would do:</p>
<pre><code class="lang-sql">WHERE name = "age"
</code></pre>
<h4 id="heading-or-operator"><code>OR</code> operator</h4>
<p>As you've probably guessed, if the logical <code>AND</code> operator is supported, the <code>OR</code> operator is probably supported as well.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, quantity, shipment_status
    <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> shipment_status = <span class="hljs-string">'out of stock'</span>
    <span class="hljs-keyword">OR</span> quantity <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">10</span> <span class="hljs-keyword">and</span> <span class="hljs-number">100</span>;
</code></pre>
<p>This query retrieves records where either the shipment_status <code>condition</code> OR the <code>quantity</code> condition are met.</p>
<p>Order of operations matter when using these operators.</p>
<p>You can group logical operations with parentheses to specify the <a target="_blank" href="https://www.mathsisfun.com/operation-order-pemdas.html">order of operations</a>.</p>
<pre><code class="lang-sql">(this AND that) OR the_other
</code></pre>
<h4 id="heading-the-in-operator">The <code>IN</code> operator</h4>
<p>Another variation to the <code>WHERE</code> clause we can utilize is the <code>IN</code> operator. <code>IN</code> returns <code>true</code> or <code>false</code> if the first operand matches any of the values in the second operand. The <code>IN</code> operator is a shorthand for multiple <code>OR</code> conditions.</p>
<p>These two queries are equivalent:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, shipment_status
    <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> shipment_status <span class="hljs-keyword">IN</span> (<span class="hljs-string">'shipped'</span>, <span class="hljs-string">'preparing'</span>, <span class="hljs-string">'out of stock'</span>);
</code></pre>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, shipment_status
    <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> shipment_status = <span class="hljs-string">'shipped'</span>
        <span class="hljs-keyword">OR</span> shipment_status = <span class="hljs-string">'preparing'</span>
        <span class="hljs-keyword">OR</span> shipment_status = <span class="hljs-string">'out of stock'</span>;
</code></pre>
<p>Hopefully, you're starting to see how querying specific data using fine-tuned SQL clauses helps reveal important insights. The larger a table becomes the harder it becomes to analyze without proper queries.</p>
<h4 id="heading-the-like-keyword">The <code>LIKE</code> keyword</h4>
<p>Sometimes we don't have the luxury of knowing exactly what it is we need to query. Have you ever wanted to look up a song or a video but you only remember part of the name? SQL provides us an option for when we're in situations <code>LIKE</code> this.</p>
<p>The <code>LIKE</code> keyword allows for the use of the <code>%</code> and <code>_</code> wildcard operators. Let's focus on <code>%</code> first.</p>
<h4 id="heading-operator"><code>%</code> Operator</h4>
<p>The <code>%</code> operator will match zero or more characters. We can use this operator within our query string to find more than just exact matches depending on where we place it.</p>
<p>Here are some examples that show how these work:</p>
<p>Product starts with "banana":</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products
<span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'banana%'</span>;
</code></pre>
<p>Product ends with "banana":</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">from</span> products
<span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'%banana'</span>;
</code></pre>
<p>Product contains "banana":</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">from</span> products
<span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'%banana%'</span>;
</code></pre>
<h3 id="heading-underscore-operator">Underscore Operator</h3>
<p>As discussed, the <code>%</code> wildcard operator matches zero or more characters. Meanwhile, the <code>_</code> wildcard operator only matches a single character.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'_oot'</span>;
</code></pre>
<p>The query above matches products like:</p>
<ul>
<li>boot</li>
<li>root</li>
<li>foot</li>
</ul>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'__oot'</span>;
</code></pre>
<p>The query above matches products like:</p>
<ul>
<li>shoot</li>
<li>groot</li>
</ul>
<h2 id="heading-chapter-6-how-to-structure-return-data-in-sql">Chapter 6: How to Structure Return Data in SQL</h2>
<h3 id="heading-the-limit-keyword">The <code>LIMIT</code> keyword</h3>
<p>Sometimes we don't want to retrieve every record from a table. For example, it's common for a production database table to have millions of rows, and <code>SELECT</code>ing all of them might crash your system. This is where the <code>LIMIT</code> keyword enters the chat.</p>
<p>The <code>LIMIT</code> keyword can be used at the end of a select statement to reduce the number of records returned.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">WHERE</span> product_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'%berry%'</span>
    <span class="hljs-keyword">LIMIT</span> <span class="hljs-number">50</span>;
</code></pre>
<p>The query above retrieves all the records from the <code>products</code> table where the name contains the word berry. If we ran this query on the Facebook database, it would almost certainly return a lot of records. </p>
<p>The <code>LIMIT</code> statement only allows the database to return up to 50 records matching the query. This means that if there aren't that many records matching the query, the <code>LIMIT</code> statement will not have an effect.</p>
<h3 id="heading-the-sql-order-by-keyword">The SQL <code>ORDER BY</code> keyword</h3>
<p>SQL also offers us the ability to sort the results of a query using <code>ORDER BY</code>. By default, the <code>ORDER BY</code> keyword sorts records by the given field in ascending order, or <code>ASC</code> for short. However, <code>ORDER BY</code> does support descending order as well with the keyword <code>DESC</code>.</p>
<h4 id="heading-examples">Examples</h4>
<p>This query returns the <code>name</code>, <code>price</code>, and <code>quantity</code> fields from the <code>products</code> table sorted by <code>price</code> in ascending order:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span>, price, quantity <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> price;
</code></pre>
<p>This query returns the <code>name</code>, <code>price</code>, and <code>quantity</code> of the products ordered by the quantity in descending order:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span>, price, quantity <span class="hljs-keyword">FROM</span> products
    <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> quantity <span class="hljs-keyword">desc</span>;
</code></pre>
<h3 id="heading-order-by-and-limit">Order By and Limit</h3>
<p>When using both <code>ORDER BY</code> and <code>LIMIT</code>, the <code>ORDER BY</code> clause must come first.</p>
<h2 id="heading-chapter-7-how-to-perform-aggregations-in-sql">Chapter 7: How to Perform Aggregations in SQL</h2>
<p>An "aggregation" is a single value that's derived by combining several other values. We performed an aggregation earlier when we used the <code>count</code> statement to count the number of records in a table.</p>
<h3 id="heading-why-use-aggregations">Why use aggregations?</h3>
<p>Data stored in a database should generally be stored <a target="_blank" href="https://wagslane.dev/posts/keep-your-data-raw-at-rest/">raw</a>. When we need to calculate some additional data from the raw data, we can use an aggregation.</p>
<p>Take the following <code>count</code> aggregation as an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">COUNT</span>(*)
<span class="hljs-keyword">FROM</span> products
<span class="hljs-keyword">WHERE</span> quantity = <span class="hljs-number">0</span>;
</code></pre>
<p>This query returns the number of products that have a <code>quantity</code> of <code>0</code>. We could store a count of the products in a separate database table, and increment/decrement it whenever we make changes to the <code>products</code> table - but that would be redundant. </p>
<p>It's much simpler to store the products in a single place (we call this a <a target="_blank" href="https://en.wikipedia.org/wiki/Single_source_of_truth">single source of truth</a>) and run an aggregation when we need to derive additional information from the raw data.</p>
<h3 id="heading-the-sum-function">The <code>SUM</code> function</h3>
<p>The <code>sum</code> aggregation function returns the sum of a set of values.</p>
<p>For example, the query below returns a single record containing a single field. The returned value is equal to the total salary being collected by all of the <code>employees</code> in the <code>employees</code> table.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">sum</span>(salary)
<span class="hljs-keyword">FROM</span> employees;
</code></pre>
<p>Which returns:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>SUM(SALARY)</td></tr>
</thead>
<tbody>
<tr>
<td>2483</td></tr>
</tbody>
</table>
</div><h3 id="heading-the-max-function">The <code>MAX</code> function</h3>
<p>As you may expect, the <code>max</code> function retrieves the <em>largest</em> value from a set of values. For example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">max</span>(price)
<span class="hljs-keyword">FROM</span> products
</code></pre>
<p>This query looks through all of the prices in the <code>products</code> table and returns the price with the largest price value. Remember it only returns the <code>price</code>, not the rest of the record. You always need to specify each field you want a query to return.</p>
<h4 id="heading-a-note-on-schema">A note on schema</h4>
<ul>
<li>The <code>sender_id</code> will be present for any transactions where the user in question (<code>user_id</code>) is receiving money (from the sender).</li>
<li>The <code>recipient_id</code> will be present for any transactions where the user in question (<code>user_id</code>) is sending money (to the recipient).</li>
</ul>
<p>In other words, a transaction can only have a <code>sender_id</code> or a <code>recipient_id</code> - not both. The presence of one or the other indicates whether money is going into or out of the user's account.</p>
<p>This <code>user_id</code>, <code>recipient_id</code>, <code>sender_id</code> schema we've designed is only one way to design a transactions database - there are other valid ways to do it. It's the one we're using, and later we'll talk more about the tradeoffs in different database design options.</p>
<h3 id="heading-the-min-function">The <code>MIN</code> function</h3>
<p>The <code>min</code> function works the same as the <code>max</code> function but finds the lowest value instead of the highest value.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> product_name, <span class="hljs-keyword">min</span>(price)
<span class="hljs-keyword">from</span> products;
</code></pre>
<p>This query returns the <code>product_name</code> and the <code>price</code> fields of the record with the lowest <code>price</code>.</p>
<h3 id="heading-the-group-by-clause">The <code>GROUP BY</code> clause</h3>
<p>There are times we need to group data based on specific values.</p>
<p>SQL offers the <code>GROUP BY</code> clause which can group rows that have similar values into "summary" rows. It returns one row for each group. The interesting part is that each group can have an aggregate function applied to it that operates only on the grouped data.</p>
<h4 id="heading-example-of-group-by">Example of <code>GROUP BY</code></h4>
<p>Imagine that we have a database with songs and albums, and we want to see how many songs are on each album. We can use a query like this:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> album_id, <span class="hljs-keyword">count</span>(song_id)
<span class="hljs-keyword">FROM</span> songs
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> album_id;
</code></pre>
<p>This query retrieves a count of all the songs on each album. One record is returned per album, and they each have their own <code>count</code>.</p>
<h3 id="heading-the-avg-function">The <code>AVG()</code> function</h3>
<p>Just like we may want to find the minimum or maximum values within a dataset, sometimes we need to know the <a target="_blank" href="https://en.wikipedia.org/wiki/Arithmetic_mean">average</a>!</p>
<p>SQL offers us the <code>AVG()</code> function. Similar to <code>MAX()</code>, <code>AVG()</code> calculates the average of all non-NULL values. </p>
<pre><code class="lang-SQL"><span class="hljs-keyword">select</span> song_name, <span class="hljs-keyword">avg</span>(song_length)
<span class="hljs-keyword">from</span> songs
</code></pre>
<p>This query returns the average <code>song_length</code> in the <code>songs</code> table.</p>
<h3 id="heading-the-having-clause">The <code>HAVING</code> clause</h3>
<p>When we need to filter the results of a <code>GROUP BY</code> query even further, we can use the <code>HAVING</code> clause. The <code>HAVING</code> clause specifies a search condition for a group.</p>
<p>The <code>HAVING</code> clause is similar to the <code>WHERE</code> clause, but it operates on groups after they've been grouped, rather than rows before they've been grouped.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> album_id, <span class="hljs-keyword">count</span>(<span class="hljs-keyword">id</span>) <span class="hljs-keyword">as</span> <span class="hljs-keyword">count</span>
<span class="hljs-keyword">FROM</span> songs
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> album_id
<span class="hljs-keyword">HAVING</span> <span class="hljs-keyword">count</span> &gt; <span class="hljs-number">5</span>;
</code></pre>
<p>This query returns the <code>album_id</code> and count of its songs, but only for albums with more than <code>5</code> songs.</p>
<h3 id="heading-having-vs-where-in-sql"><code>HAVING</code> vs <code>WHERE</code> in SQL</h3>
<p>It's fairly common for developers to get confused about the difference between the <code>HAVING</code> and the <code>WHERE</code> clauses - they're pretty similar after all.</p>
<p>The difference is fairly simple in actuality:</p>
<ul>
<li>A <code>WHERE</code> condition is applied to all the data in a query before it's grouped by a <code>GROUP BY</code> clause.</li>
<li>A <code>HAVING</code> condition is only applied to the grouped rows that are returned after a <code>GROUP BY</code> is applied.</li>
</ul>
<p>This means that if you want to filter on the result of an aggregation, you need to use <code>HAVING</code>. If you want to filter on a value that's present in the raw data, you should use a simple <code>WHERE</code> clause.</p>
<h3 id="heading-the-round-function">The <code>ROUND</code> function</h3>
<p>Sometimes we need to <a target="_blank" href="https://en.wikipedia.org/wiki/Rounding">round</a> some numbers, particularly when working with the results of an aggregation. We can use the <code>ROUND()</code> function to get the job done.</p>
<p>The SQL <code>round()</code> function allows you to specify both the value you wish to round and the precision to which you wish to round it:</p>
<pre><code class="lang-SQL">round(value, precision)
</code></pre>
<p>If no precision is given, SQL will round the value to the nearest whole value:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">select</span> song_name, <span class="hljs-keyword">round</span>(<span class="hljs-keyword">avg</span>(song_length), <span class="hljs-number">1</span>)
<span class="hljs-keyword">from</span> songs
</code></pre>
<p>This query returns the average <code>song_length</code> from the <code>songs</code> table, rounded to a single decimal point.</p>
<h2 id="heading-chapter-8-sql-subqueries">Chapter 8: SQL Subqueries</h2>
<h3 id="heading-subqueries">Subqueries</h3>
<p>Sometimes a single query is not enough to retrieve the specific records we need.</p>
<p>It is possible to run a query on the result set of another query - a query within a query! This is called "query-ception"... erm... I mean a "subquery".</p>
<p>Subqueries can be very useful in a number of situations when trying to retrieve specific data that wouldn't be accessible by simply querying a single table.</p>
<h4 id="heading-how-to-retreive-data-from-multiple-tables">How to retreive data from multiple tables</h4>
<p>Here is an example of a subquery:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, song_name, artist_id
<span class="hljs-keyword">FROM</span> songs
<span class="hljs-keyword">WHERE</span> artist_id <span class="hljs-keyword">IN</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>
    <span class="hljs-keyword">FROM</span> artists
    <span class="hljs-keyword">WHERE</span> artist_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'Rick%'</span>
);
</code></pre>
<p>In this hypothetical database, the query above selects all of the <code>song_id</code>s, <code>song_name</code>s, and <code>artist_id</code>s from the <code>songs</code> table that are written by artists whose name starts with "Rick". Notice that the subquery allows us to use information from a different table - in this case the <code>artists</code> table.</p>
<h4 id="heading-subquery-syntax">Subquery syntax</h4>
<p>The only syntax unique to a subquery is the parentheses surrounding the nested query. The <code>IN</code> operator could be different, for example, we could use the <code>=</code> operator if we expect a single value to be returned.</p>
<p>Here's an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, song_name, artist_id
<span class="hljs-keyword">FROM</span> songs
<span class="hljs-keyword">WHERE</span> artist_id <span class="hljs-keyword">IN</span> (
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>
    <span class="hljs-keyword">FROM</span> artists
    <span class="hljs-keyword">WHERE</span> artist_name <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'Rick%'</span>
);
</code></pre>
<h3 id="heading-no-tables-necessary">No tables necessary</h3>
<p>When working on a back-end application, this doesn't come up often, but it's important to remember that <strong>SQL is a full programming language</strong>. We usually use it to interact with data stored in tables, but it's quite flexible and powerful.</p>
<p>For example, you can <code>SELECT</code> information that's simply calculated, with no tables necessary.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> <span class="hljs-number">5</span> + <span class="hljs-number">10</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">sum</span>;
</code></pre>
<h2 id="heading-chapter-9-database-normalization">Chapter 9: Database Normalization</h2>
<h3 id="heading-table-relationships">Table Relationships</h3>
<p>Relational databases are powerful because of the relationships between the tables. These relationships help us to keep our databases clean and efficient. </p>
<p>A relationship between tables assumes that one of these tables has a <code>foreign key</code> that references the <code>primary key</code> of another table.</p>
<p>@<a target="_blank" href="https://www.youtube.com/watch?v=WJTdg1AsSz0">youtube</a></p>
<h4 id="heading-types-of-relationships">Types of Relationships</h4>
<p>There are 3 primary types of relationships in a relational database:</p>
<ol>
<li>One-to-one</li>
<li>One-to-many</li>
<li>Many-to-many</li>
</ol>
<p><img src="https://i.imgur.com/u4i6XdL.png" alt="relationships" width="763" height="340" loading="lazy"></p>
<h3 id="heading-one-to-one">One-to-one</h3>
<p>A <code>one-to-one</code> relationship most often manifests as a field or set of fields on a row in a table. For example, a <code>user</code> will have exactly one <code>password</code>.</p>
<p>Settings fields might be another example of a one-to-one relationship. A user will have exactly one <code>email_preference</code> and exactly one <code>birthday</code>.</p>
<h3 id="heading-one-to-many">One to many</h3>
<p>When talking about the relationships between tables, a one-to-many relationship is probably the most commonly used relationship. </p>
<p>A one-to-many relationship occurs when a single record in one table is related to potentially many records in another table. </p>
<p>Note that the one-&gt;many relation only goes one way, a record in the second table can not be related to multiple records in the first table!</p>
<h4 id="heading-examples-of-one-to-many-relationships">Examples of one-to-many relationships</h4>
<ul>
<li>A <code>customers</code> table and a <code>orders</code> table. Each customer has <code>0</code>, <code>1</code>, or many orders that they've placed.</li>
<li>A <code>users</code> table and a <code>transactions</code> table. Each <code>user</code> has <code>0</code>, <code>1</code>, or many transactions that taken part in.</li>
</ul>
<h3 id="heading-many-to-many">Many to many</h3>
<p>A many-to-many relationship occurs when multiple records in one table can be related to multiple records in another table.</p>
<h4 id="heading-examples-of-many-to-many-relationships">Examples of many-to-many relationships</h4>
<ul>
<li>A <code>products</code> table and a <code>suppliers</code> table - Products may have <code>0</code> to many suppliers, and suppliers can supply <code>0</code> to many products.</li>
<li>A <code>classes</code> table and a <code>students</code> table - Students can take potentially many classes and classes can have many students enrolled.</li>
</ul>
<h4 id="heading-joining-tables">Joining tables</h4>
<p>Joining tables helps define many-to-many relationships between data in a database. As an example, when defining the relationship above between products and suppliers, we would define a joining table called <code>products_suppliers</code> that contains the primary keys from the tables to be joined.</p>
<p>Then, when we want to see if a supplier supplies a specific product, we can look in the joining table to see if the ids share a row.</p>
<h4 id="heading-unique-constraints-across-2-fields">Unique constraints across 2 fields</h4>
<p>When enforcing specific schema constraints we may need to enforce the <code>UNIQUE</code> constraint across two different fields.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> product_suppliers (
  product_id <span class="hljs-built_in">INTEGER</span>,
  supplier_id <span class="hljs-built_in">INTEGER</span>,
  <span class="hljs-keyword">UNIQUE</span>(product_id, supplier_id)
);
</code></pre>
<p>This ensures that we can have multiple rows with the same <code>product_id</code> or <code>supplier_id</code>, but we can't have two rows where both the <code>product_id</code> and <code>supplier_id</code> are the same.</p>
<h3 id="heading-database-normalization">Database normalization</h3>
<p>Database normalization is a method for structuring your database schema in a way that helps:</p>
<ul>
<li>Improve data integrity</li>
<li>Reduce data redundancy</li>
</ul>
<h4 id="heading-what-is-data-integrity">What is data integrity?</h4>
<p>"Data integrity" refers to the accuracy and consistency of data. For example, if a user's age is stored in a database, rather than their birthday, that data becomes incorrect automatically with the passage of time.</p>
<p>It would be better to store a birthday and calculate the age as needed.</p>
<h4 id="heading-what-is-data-redundancy">What is data redundancy?</h4>
<p>"Data redundancy" occurs when the same piece of data is stored in multiple places. For example: saving the same file multiple times to different hard drives.</p>
<p>Data redundancy can be problematic, especially when data in one place is changed such that the data is no longer consistent across all copies of that data.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/U3L4NYNwb6k" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-normal-forms">Normal Forms</h3>
<p>The creator of "database normalization", <a target="_blank" href="https://en.wikipedia.org/wiki/Edgar_F._Codd">Edgar F. Codd</a>, described different "normal forms" a database can adhere to. We'll talk about the most common ones.</p>
<ul>
<li>First normal form (1NF)</li>
<li>Second normal form (2NF)</li>
<li>Third normal form (3NF)</li>
<li>Boyce-Codd normal form (BCNF)</li>
</ul>
<p><img src="https://i.imgur.com/CpDOeej.png" alt="normal forms" width="300" height="275" loading="lazy"></p>
<p>In short, 1st normal form is the least "normalized" form, and Boyce-Codd is the most "normalized" form.</p>
<p>The more normalized a database, the better its data integrity, and the less duplicate data you'll have.</p>
<h4 id="heading-in-the-context-of-normal-forms-primary-key-means-something-a-bit-different">In the context of normal forms, "primary key" means something a bit different</h4>
<p>In the context of database normalization, we're going to use the term "primary key" slightly differently. When we're talking about SQLite, a "primary key" is a single column that uniquely identifies a row.</p>
<p>When we're talking more generally about data normalization, the term "primary key" means the collection of columns that uniquely identify a row. That can be a single column, but it can actually be any number of columns. A primary key is the minimum number of columns needed to uniquely identify a row in a table. </p>
<p>If you think back to the many-to-many joining table <code>product_suppliers</code>, that table's "primary key" was actually a combination of the 2 ids, <code>product_id</code> and <code>supplier_id</code>:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> product_suppliers (
    product_id <span class="hljs-built_in">INTEGER</span>,
    supplier_id <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-keyword">UNIQUE</span>(product_id, supplier_id)
);
</code></pre>
<h3 id="heading-1st-normal-form-1nf">1st Normal Form (1NF)</h3>
<p>To be compliant with <a target="_blank" href="https://en.wikipedia.org/wiki/First_normal_form">first normal form</a>, a database table simply needs to follow 2 rules:</p>
<ul>
<li>It must have a unique primary key.</li>
<li>A cell can't have a nested table as its value (depending on the database you're using, this may not even be possible)</li>
</ul>
<h4 id="heading-example-of-not-1st-normal-form">Example of NOT 1st normal form</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>name</td><td>age</td><td>email</td></tr>
</thead>
<tbody>
<tr>
<td>Lane</td><td>27</td><td>lane@boot.dev</td></tr>
<tr>
<td>Lane</td><td>27</td><td>lane@boot.dev</td></tr>
<tr>
<td>Allan</td><td>27</td><td>allan@boot.dev</td></tr>
</tbody>
</table>
</div><p>This table does not adhere to 1NF. It has two identical rows, so there isn't a unique primary key for each row.</p>
<h4 id="heading-example-of-1st-normal-form">Example of 1st normal form</h4>
<p>The simplest way (but not the only way) to get into first normal form is to add a unique <code>id</code> column.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>id</td><td>name</td><td>age</td><td>email</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>Lane</td><td>27</td><td>lane@boot.dev</td></tr>
<tr>
<td>2</td><td>Lane</td><td>27</td><td>lane@boot.dev</td></tr>
<tr>
<td>3</td><td>Allan</td><td>27</td><td>allan@boot.dev</td></tr>
</tbody>
</table>
</div><p>It's worth noting that if you create a "primary key" by ensuring that two columns are always "unique together" that works too.</p>
<h4 id="heading-you-should-almost-never-design-a-table-that-doesnt-adhere-to-1nf">You should <em>almost</em> never design a table that doesn't adhere to 1NF</h4>
<p>First normal form is simply a good idea. I've never built a database schema where each table isn't at least in first normal form.</p>
<h3 id="heading-2nd-normal-form-2nf">2nd Normal Form (2NF)</h3>
<p>A table in <a target="_blank" href="https://en.wikipedia.org/wiki/Second_normal_form">second normal form</a> follows all the rules of 1st normal form, and one additional rule:</p>
<ul>
<li>All columns that are not part of the primary key are dependent on the entire primary key, and not just one of the columns in the primary key.</li>
</ul>
<h4 id="heading-example-of-1st-nf-but-not-2nd-nf">Example of 1st NF, but not 2nd NF</h4>
<p>In this table, the primary key is a combination of <code>first_name</code> + <code>last_name</code>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>first_name</td><td>last_name</td><td>first_initial</td></tr>
</thead>
<tbody>
<tr>
<td>Lane</td><td>Wagner</td><td>l</td></tr>
<tr>
<td>Lane</td><td>Small</td><td>l</td></tr>
<tr>
<td>Allan</td><td>Wagner</td><td>a</td></tr>
</tbody>
</table>
</div><p>This table does not adhere to 2NF. The <code>first_initial</code> column is entirely dependent on the <code>first_name</code> column, rendering it redundant.</p>
<h4 id="heading-example-of-2nd-normal-form">Example of 2nd normal form</h4>
<p>One way to convert the table above to 2NF is to add a new table that maps a <code>first_name</code> directly to its <code>first_initial</code>. This removes any duplicates:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>first_name</td><td>last_name</td></tr>
</thead>
<tbody>
<tr>
<td>Lane</td><td>Wagner</td></tr>
<tr>
<td>Lane</td><td>Small</td></tr>
<tr>
<td>Allan</td><td>Wagner</td></tr>
</tbody>
</table>
</div><div class="hn-table">
<table>
<thead>
<tr>
<td>first_name</td><td>first_initial</td></tr>
</thead>
<tbody>
<tr>
<td>Lane</td><td>l</td></tr>
<tr>
<td>Allan</td><td>a</td></tr>
</tbody>
</table>
</div><h4 id="heading-2nf-is-usually-a-good-idea">2NF is <em>usually</em> a good idea</h4>
<p>You should probably default to keeping your tables in second normal form. That said, there are good reasons to deviate from it, particularly for performance reasons. The reason being that when you have query a second table to get additional data it can take a bit longer.</p>
<p>My rule of thumb is:</p>
<blockquote>
<p>Optimize for data integrity and data de-duplication first. If you have speed issues, de-normalize accordingly.</p>
</blockquote>
<h3 id="heading-3rd-normal-form-3nf">3rd Normal Form (3NF)</h3>
<p>A table in <a target="_blank" href="https://en.wikipedia.org/wiki/Third_normal_form">3rd normal form</a> follows all the rules of 2nd normal form, and one additional rule:</p>
<ul>
<li>All columns that aren't part of the primary are dependent solely on the primary key.</li>
</ul>
<p>Notice that this is only slightly different from second normal form. In second normal form we can't have a column completely dependent on a part of the primary key, and in third normal form we can't have a column that is entirely dependent on anything that isn't the entire primary key.</p>
<h4 id="heading-example-of-2nd-nf-but-not-3rd-nf">Example of 2nd NF, but not 3rd NF</h4>
<p>In this table, the primary key is simply the <code>id</code> column.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>id</td><td>name</td><td>first_initial</td><td>email</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>Lane</td><td>l</td><td>lane.works@example.com</td></tr>
<tr>
<td>2</td><td>Breanna</td><td>b</td><td>breanna@example.com</td></tr>
<tr>
<td>3</td><td>Lane</td><td>l</td><td>lane.right@example.com</td></tr>
</tbody>
</table>
</div><p>This table is in 2nd normal form because <code>first_initial</code> is not dependent on a part of the primary key. However, because it is dependent on the <code>name</code> column it doesn't adhere to 3rd normal form.</p>
<h4 id="heading-example-of-3rd-normal-form">Example of 3rd normal form</h4>
<p>The way to convert the table above to 3NF is to add a new table that maps a <code>name</code> directly to its <code>first_initial</code>. Notice how similar this solution is to 2NF.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>id</td><td>name</td><td>email</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>Lane</td><td>lane.works@example.com</td></tr>
<tr>
<td>2</td><td>Breanna</td><td>breanna@example.com</td></tr>
<tr>
<td>3</td><td>Lane</td><td>lane.right@example.com</td></tr>
</tbody>
</table>
</div><div class="hn-table">
<table>
<thead>
<tr>
<td>name</td><td>first_initial</td></tr>
</thead>
<tbody>
<tr>
<td>Lane</td><td>l</td></tr>
<tr>
<td>Breanna</td><td>b</td></tr>
</tbody>
</table>
</div><h4 id="heading-3nf-is-usually-a-good-idea">3NF is <em>usually</em> a good idea</h4>
<p>The same exact rule of thumb applies to the second and third normal forms.</p>
<blockquote>
<p>Optimize for data integrity and data de-duplication first by adhering to 3NF. If you have speed issues, de-normalize accordingly.</p>
</blockquote>
<p>Remember the <a target="_blank" href="https://www.sqlitetutorial.net/sqlite-functions/sqlite-iif/">IIF function</a> and the <code>AS</code> clause.</p>
<h3 id="heading-boyce-codd-normal-form-bcnf">Boyce-Codd Normal Form (BCNF)</h3>
<p>A table in <a target="_blank" href="https://en.wikipedia.org/wiki/Boyce%E2%80%93Codd_normal_form">Boyce-Codd normal form</a> (created by <a target="_blank" href="https://en.wikipedia.org/wiki/Raymond_F._Boyce">Raymond F Boyce</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/Edgar_F._Codd">Edgar F Codd</a>) follows all the rules of 3rd normal form, plus one additional rule:</p>
<ul>
<li>A column that's part of a primary key can not be entirely dependent on a column that's not part of that primary key.</li>
</ul>
<p>This only comes into play when there are multiple possible primary key combinations that overlap. Another name for this is "overlapping candidate keys".</p>
<p>Only in rare cases does a table in third normal form not meet the requirements of Boyce-Codd normal form.</p>
<h4 id="heading-example-of-3rd-nf-but-not-boyce-codd-nf">Example of 3rd NF, but not Boyce-Codd NF</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>release_year</td><td>release_date</td><td>sales</td><td>name</td></tr>
</thead>
<tbody>
<tr>
<td>2001</td><td>2001-01-02</td><td>100</td><td>Kiss me tender</td></tr>
<tr>
<td>2001</td><td>2001-02-04</td><td>200</td><td>Bloody Mary</td></tr>
<tr>
<td>2002</td><td>2002-04-14</td><td>100</td><td>I wanna be them</td></tr>
<tr>
<td>2002</td><td>2002-06-24</td><td>200</td><td>He got me</td></tr>
</tbody>
</table>
</div><p>The interesting thing here is that there are 3 possible primary keys:</p>
<ul>
<li><code>release_year</code> + <code>sales</code></li>
<li><code>release_date</code> + <code>sales</code></li>
<li><code>name</code></li>
</ul>
<p>This means that by definition this table is in 2nd and 3rd normal form because those forms only restrict how dependent a column that is not part of a primary key can be.</p>
<p>This table is not in Boyce-Codd's normal form because <code>release_year</code> is entirely dependent on <code>release_date</code>.</p>
<h4 id="heading-example-of-boyce-codd-normal-form">Example of Boyce-Codd normal form</h4>
<p>The easiest way to fix the table in our example is to simply remove the duplicate data from <code>release_date</code>. Let's make that column <code>release_day_and_month</code>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>release_year</td><td>release_day_and_month</td><td>sales</td><td>name</td></tr>
</thead>
<tbody>
<tr>
<td>2001</td><td>01-02</td><td>100</td><td>Kiss me tender</td></tr>
<tr>
<td>2001</td><td>02-04</td><td>200</td><td>Bloody Mary</td></tr>
<tr>
<td>2002</td><td>04-14</td><td>100</td><td>I wanna be them</td></tr>
<tr>
<td>2002</td><td>06-24</td><td>200</td><td>He got me</td></tr>
</tbody>
</table>
</div><h4 id="heading-bcnf-is-usually-a-good-idea">BCNF is <em>usually</em> a good idea</h4>
<p>The same exact rule of thumb applies to the 2nd, 3rd and Boyce-Codd normal forms. That said, it's unlikely you'll see BCNF-specific issues in practice.</p>
<blockquote>
<p>Optimize for data integrity and data de-duplication first by adhering to Boyce-Codd normal form. If you have speed issues, de-normalize accordingly.</p>
</blockquote>
<h3 id="heading-normalization-review">Normalization Review</h3>
<p>In my opinion, the exact definitions of 1st, 2nd, 3rd and Boyce-Codd normal forms simply are not all that important in your work as a back-end developer.</p>
<p>However, what is important is to understand the basic principles of data integrity and data redundancy that the normal forms teach us. </p>
<p>Let's go over some rules of thumb that you should commit to memory - they'll serve you well when you design databases and even just in coding interviews.</p>
<h4 id="heading-rules-of-thumb-for-database-design">Rules of thumb for database design</h4>
<ol>
<li>Every table should always have a unique identifier (primary key)</li>
<li>90% of the time, that unique identifier will be a single column named <code>id</code></li>
<li>Avoid duplicate data</li>
<li>Avoid storing data that is completely dependent on other data. Instead, compute it on the fly when you need it.</li>
<li>Keep your schema as simple as you can. Optimize for a normalized database first. Only denormalize for speed's sake when you start to run into performance problems.</li>
</ol>
<p>We'll talk more about speed optimization in a later chapter.</p>
<h2 id="heading-chapter-10-how-to-join-tables-in-sql">Chapter 10: How to Join Tables in SQL</h2>
<p>Joins are one of the most important features that SQL offers. Joins allow us to make use of the relationships we have set up between our tables. In short, joins allow us to query multiple tables at the same time.</p>
<h3 id="heading-inner-join"><code>INNER JOIN</code></h3>
<p>The simplest and most common type of join in SQL is the <code>INNER JOIN</code>. By default, a <code>JOIN</code> command is an <code>INNER JOIN</code>. </p>
<p>An <code>INNER JOIN</code> returns all of the records in <code>table_a</code> that have matching records in <code>table_b</code>, as demonstrated by the following Venn diagram.</p>
<p><img src="https://i.imgur.com/wgxAmhA.png" alt="inner join" width="421" height="293" loading="lazy"></p>
<h4 id="heading-the-on-clause">The <code>ON</code> clause</h4>
<p>In order to perform a join, we need to tell the database which fields should be "matched up". The  <code>ON</code> clause is used to specify these columns to join.</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> employees
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> departments 
<span class="hljs-keyword">ON</span> employees.department_id = departments.id;
</code></pre>
<p>The query above returns all the fields from both tables. The <code>INNER</code> keyword doesn't have anything to do with the number of columns returned - it only affects the number of rows returned.</p>
<h3 id="heading-namespacing-on-tables">Namespacing on Tables</h3>
<p>When working with multiple tables, you can specify which table a field exists on using a <code>.</code>. For example:</p>
<p><code>table_name.column_name</code></p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> students.name, classes.name
<span class="hljs-keyword">FROM</span> students
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> classes <span class="hljs-keyword">on</span> classes.class_id = students.class_id;
</code></pre>
<p>The above query returns the <code>name</code> field from the <code>students</code> table and the <code>name</code> field from the <code>classes</code> table. </p>
<h3 id="heading-left-join"><code>LEFT JOIN</code></h3>
<p>A <code>LEFT JOIN</code> will return every record from <code>table_a</code> regardless of whether or not any of those records have a match in <code>table_b</code>. A left join will also return any matching records from <code>table_b</code>. </p>
<p>Here is a Venn diagram to help visualize the effect of a <code>LEFT JOIN</code>.</p>
<p><img src="https://i.imgur.com/mNbhWfM.png" alt="left-join" width="292" height="178" loading="lazy"></p>
<p>A small trick you can do to make writing the SQL query easier is define an <a target="_blank" href="https://en.wikipedia.org/wiki/Alias_(SQL)">alias</a> for each table. Here's an example:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">SELECT</span> e.name, d.name
<span class="hljs-keyword">FROM</span> employees e
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> departments d
<span class="hljs-keyword">ON</span> e.department_id = d.id;
</code></pre>
<p>Notice the simple alias declarations <code>e</code> and <code>d</code> for <code>employees</code> and <code>departments</code> respectively.</p>
<p>Some developers do this to make their queries less verbose. That said, I personally hate it because single-letter variables are harder to understand the meaning of.</p>
<h3 id="heading-right-join"><code>RIGHT JOIN</code></h3>
<p>A <code>RIGHT JOIN</code> is, as you may expect, the opposite of a <code>LEFT JOIN</code>. It returns all records from <code>table_b</code> regardless of matches, and all matching records between the two tables.</p>
<p><img src="https://i.imgur.com/LG6Y43j.png" alt="right-join" width="652" height="352" loading="lazy"></p>
<h4 id="heading-sqlite-restriction">SQLite Restriction</h4>
<p>SQLite does not support right joins, but many dialects of SQL do. If you think about it, a <code>RIGHT JOIN</code> is just a <code>LEFT JOIN</code> with the order of the tables switched, so it's not a big deal that SQLite doesn't support the syntax.</p>
<h3 id="heading-full-join"><code>FULL JOIN</code></h3>
<p>A <code>FULL JOIN</code> combines the result set of the <code>LEFT JOIN</code> and <code>RIGHT JOIN</code> commands. It returns all records from both from <code>table_a</code> and <code>table_b</code> regardless of whether or not they have matches.</p>
<p><img src="https://i.imgur.com/Kk3k1Ub.png" alt="Full-join" width="606" height="344" loading="lazy"></p>
<h4 id="heading-sqlite">SQLite</h4>
<p>Like <code>RIGHT JOIN</code>s, SQLite doesn't support <code>FULL JOIN</code>s but they are still important to know.</p>
<h2 id="heading-chapter-11-database-performance">Chapter 11: Database Performance</h2>
<h3 id="heading-sql-indexes">SQL Indexes</h3>
<p>An index is an in-memory structure that ensures that queries we run on a database are performant, that is to say, they run quickly. </p>
<p>If you've learned about data structures, most database indexes are just <a target="_blank" href="https://en.wikipedia.org/wiki/Binary_tree">binary trees</a>. The binary tree can be stored in <a target="_blank" href="https://en.wikipedia.org/wiki/Random-access_memory">ram</a> as well as on <a target="_blank" href="https://en.wikipedia.org/wiki/Computer_data_storage">disk</a>, and it makes it easy to lookup the location of an entire row.</p>
<p><code>PRIMARY KEY</code> columns are indexed by default, ensuring you can look up a row by its <code>id</code> very quickly. But if you have other columns that you want to be able to do quick lookups on, you'll need to index them.</p>
<h4 id="heading-create-index"><code>CREATE INDEX</code></h4>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> index_name <span class="hljs-keyword">on</span> table_name (column_name);
</code></pre>
<p>It's fairly common to name an index after the column it's created on with a suffix of <code>_idx</code>.</p>
<h3 id="heading-index-review">Index Review</h3>
<p>As we discussed, an index is a data structure that can perform quick lookups. By indexing a column, we create a new in-memory structure, usually a binary-tree, where the values in the indexed column are sorted into the tree to keep lookups fast. </p>
<p>In terms of Big-O complexity, a binary tree index ensures that lookups are <a target="_blank" href="https://en.wikipedia.org/wiki/Big_O_notation">O(log(n))</a>.</p>
<h4 id="heading-shouldnt-we-index-everything-we-can-make-the-database-ultra-fast">Shouldn't we index everything? We can make the database ultra-fast!</h4>
<p>While indexes make specific kinds of lookups much faster, they also add performance overhead - they can slow down a database in other ways. </p>
<p>Think about it: if you index every column, you could have hundreds of binary trees in memory. That needlessly bloats the memory usage of your database. It also means that each time you insert a record, that record needs to be added to many trees - slowing down your insert speed.</p>
<p>The rule of thumb is simple:</p>
<blockquote>
<p>Add an index to columns you know you'll be doing frequent lookups on. Leave everything else un-indexed. You can always add indexes later.</p>
</blockquote>
<h3 id="heading-multi-column-indexes">Multi-column indexes</h3>
<p>Multi-column indexes are useful for the exact reason you might think - they speed up lookups that depend on multiple columns. </p>
<h4 id="heading-create-index-1"><code>CREATE INDEX</code></h4>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> first_name_last_name_age_idx
<span class="hljs-keyword">ON</span> <span class="hljs-keyword">users</span> (first_name, last_name, age);
</code></pre>
<p>A multi-column index is sorted by the first column first, the second column next, and so forth. A lookup on only the first column in a multi-column index gets almost all of the performance improvements that it would get from its own single-column index. But lookups on only the second or third column will have very degraded performance.</p>
<h4 id="heading-rule-of-thumb">Rule of thumb</h4>
<p>Unless you have specific reasons to do something special, only add multi-column indexes if you're doing frequent lookups on a specific combination of columns.</p>
<h3 id="heading-denormalizing-for-speed">Denormalizing for speed</h3>
<p>I left you with a cliffhanger in the "normalization" chapter. As it turns out, data integrity and deduplication come at a cost, and that cost is usually speed.</p>
<p>Joining tables together, using subqueries, performing aggregations, and running post-hoc calculations all take time. At very large scales these advanced techniques can actually take a huge performance toll on an application - sometimes grinding the database server to a halt.</p>
<p>Storing duplicate information can drastically speed up an application that needs to look it up in different ways. For example, if you store a user's country information right on their user record, no expensive join is required to load their profile page.</p>
<p>That said, denormalize at your own risk. Denormalizing a database incurs a large risk of inaccurate and buggy data.</p>
<p>In my opinion, it should be used as a kind of "last resort" in the name of speed.</p>
<h3 id="heading-sql-injection-1">SQL Injection</h3>
<p>SQL is a very common way hackers attempt to cause damage or breach a database. One of my favorite <a target="_blank" href="https://xkcd.com/327/">XKCD</a> comics of all time demonstrates the problem:</p>
<p><img src="https://bobby-tables.com/img/xkcd.png" alt="bobby tables" width="666" height="205" loading="lazy"></p>
<p>The joke here is that if someone was using this query:</p>
<pre><code class="lang-SQL"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> students(<span class="hljs-keyword">name</span>) <span class="hljs-keyword">VALUES</span> (?);
</code></pre>
<p>And the "name" of a student was <code>'Robert'); DROP TABLE students;--</code> then the resulting SQL query would look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> students(<span class="hljs-keyword">name</span>) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Robert'</span>); <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> students;<span class="hljs-comment">--)</span>
</code></pre>
<p>As you can see, this is actually 2 queries! The first one inserts "Robert" into the database, and the second one deletes the students table!</p>
<h4 id="heading-how-do-we-protect-against-sql-injection">How do we protect against SQL injection?</h4>
<p>You need to be aware of SQL injection attacks, but to be honest the solution these days is to simply use a modern SQL library that sanitizes SQL inputs. We don't often need to sanitize inputs by hand at the application level anymore.</p>
<p>For example, the Go standard library's SQL packages automatically protects your inputs against SQL attacks if you <a target="_blank" href="https://go.dev/doc/database/sql-injection">use it properly</a>. In short, don't interpolate user input into raw strings yourself - make sure your database library has a way to sanitize inputs, and pass it those raw values.</p>
<h2 id="heading-congratulations-on-making-it-to-the-end">Congratulations on making it to the end!</h2>
<p>If you're interested in doing the interactive coding assignments and quizzes for this course, you can check out the <a target="_blank" href="https://www.boot.dev/learn/learn-sql">Learn SQL Course</a> course over on <a target="_blank" href="https://www.boot.dev/">Boot.dev</a></p>
<p>This course is a part of my full back-end developer career path, made up of other courses and projects if you're interested in checking those out.</p>
<p>If you want to see the other content I'm creating related to web development, check out some of my links below:</p>
<p><a target="_blank" href="https://www.backendbanter.fm/">Lane's Podcast: Backend Banter</a>
<a target="_blank" href="https://twitter.com/wagslane">Lane on Twitter</a>
<a target="_blank" href="https://www.youtube.com/@bootdotdev">Lane on YouTube</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform CRUD Operations – JavaScript and SQL Example ]]>
                </title>
                <description>
                    <![CDATA[ For the most part, interactive website architectures will involve generating or dispensing data of one sort or another. You can certainly use HTML forms to collect user input. But the kind of web form that's described here will only take you so far. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-perform-crud-operations-js-and-sql/</link>
                <guid isPermaLink="false">66b995f17bb37b73c3f3c4e5</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Thu, 03 Aug 2023 20:41:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/5f9ca0b7740569d1a4ca4a58.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For the most part, interactive website architectures will involve generating or dispensing data of one sort or another. You can certainly use HTML forms to collect user input. But the kind of web form <a target="_blank" href="https://www.freecodecamp.org/news/creating-html-forms/">that's described here</a> will only take you so far. </p>
<p>What we really need is a way to reliably store and manipulate our data within the application environment. </p>
<p>In this article, I'm going to show you how to connect a back end database to your data collection process. The plan involves tossing some HTML, JavaScript, and the tiny database engine SQLite into a bowl, mixing vigorously, and seeing what comes out. </p>
<p>This article comes from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-web-development-essentials-exam-study-guide/?referralCode=C92570BCBB38302A9257">my Complete LPI Web Development Essentials Study Guide course</a>. If you'd like, you can follow the video version here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/yf2RJmpMEiI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>As you may already know, the SQL in SQLite stands for <em>structured query language</em>. This means that the syntax you'll use for interacting with a SQLite database will closely parallel how you'd do it with databases like MariaDB, Amazon Aurora, Oracle, or Microsoft's SQL Server. If you've got experience with any of those, you'll be right at home here.</p>
<p>Why are we going to use SQLite here? Because it's a very popular choice for the kind of work you're likely to undertake in a web environment. </p>
<p>You'll need to create a new directory on your machine along with some files with JavaScript code. We'll learn how to create, modify, and delete records in a SQLite database. </p>
<p>I could incorporate all those actions into a single file, of course, but I think breaking them out into multiple files will make it easier to understand what's going on.</p>
<h2 id="heading-connecting-to-a-database-and-creating-a-table">Connecting to a Database and Creating a Table</h2>
<p>Here's what the first file will look like:</p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();

<span class="hljs-comment">// Create/connect to the database</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);

<span class="hljs-comment">// Create a table</span>
db.run(<span class="hljs-string">`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    age INTEGER
)`</span>);

<span class="hljs-comment">// Insert data</span>
<span class="hljs-keyword">const</span> insertQuery = <span class="hljs-string">`INSERT INTO users (name, age) VALUES (?, ?)`</span>;
<span class="hljs-keyword">const</span> name = <span class="hljs-string">'Trevor'</span>;
<span class="hljs-keyword">const</span> age = <span class="hljs-number">5</span>;
db.run(insertQuery, [name, age], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Inserted data with id <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastID}</span>`</span>);
    }
});

<span class="hljs-comment">// Close the database connection</span>
db.close();
</code></pre><p>We begin by loading the sqlite3 module as <code>sqlite3</code> and then creating the <code>db</code> variable to represent our new database instance. The database will be called <code>mydatabase.db</code>. </p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);
</code></pre><p>If there isn't a database using that name in our local directory, the code will create one, otherwise it'll just connect to the one that's there already.</p>
<p>Since this is our first run, I'll create a new table within the <code>mydatabase.db</code> database. There will be three keys in our table: <code>id</code>, <code>name</code>, and <code>age</code>. </p>
<pre><code>db.run(<span class="hljs-string">`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    age INTEGER
)`</span>);
</code></pre><p>As you can see, <code>id</code> will be the primary key that we'll use to reference individual records. </p>
<p>We defined the data type of each key: integer, text and, again, integer. This definition is something we only need to do once. But we do want to get it right, because changing it later, after we've already added data, can be tricky.</p>
<h2 id="heading-inserting-new-data-into-a-table">Inserting New Data into a Table</h2>
<p>In this section, we'll will add a new record to the table using the SQL <code>INSERT</code> command.</p>
<pre><code><span class="hljs-keyword">const</span> insertQuery = <span class="hljs-string">`INSERT INTO users (name, age) VALUES (?, ?)`</span>;
<span class="hljs-keyword">const</span> name = <span class="hljs-string">'Trevor'</span>;
<span class="hljs-keyword">const</span> age = <span class="hljs-number">5</span>;
db.run(insertQuery, [name, age], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Inserted data with id <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastID}</span>`</span>);
    }
});
</code></pre><p>You'll probably discover that official SQL documentation always capitalizes key syntax terms like <code>INSERT</code> and <code>SELECT</code>. That's a useful best practice, but it's not actually necessary. As a rule, I'm way too lazy to bother.</p>
<p>The query itself is templated as <code>insertQuery</code>, with the <code>name</code> and <code>age</code> details added as constants in the lines that follow. </p>
<p>The <code>db.run</code> method, using the <code>insertQuery</code> constant and those two values (<code>name</code> and <code>age</code>) as attributes, is then executed. Based on the success or failure of the operation, log messages will be generated.</p>
<p>But hang on for a moment. What's with those question marks after declaring <code>insertQuery</code>? And why did we need to break this process into two parts? </p>
<p>This is actually an important security practice known as an escape variable. With this in place, when the <code>db.run()</code> method executes the prepared statement, it'll automatically handle the escaping of the variable value, preventing SQL injection.</p>
<p>Lastly, we close down the connection:</p>
<pre><code>db.close();
</code></pre><h2 id="heading-modifying-data">Modifying Data</h2>
<p>Now let's see how the "modify" code works. Like before, we create a SQLite3 constant and then connect to our database. </p>
<p>This time, however, our table already exists, so we can go straight to the "modify" section.</p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();

<span class="hljs-comment">// Create/connect to the database</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);

<span class="hljs-comment">// Modify data</span>
<span class="hljs-keyword">const</span> updateQuery = <span class="hljs-string">`UPDATE users SET age = ? WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> updatedAge = <span class="hljs-number">30</span>;
<span class="hljs-keyword">const</span> updatedName = <span class="hljs-string">'name2'</span>;
db.run(updateQuery, [updatedAge, updatedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Modified <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});

<span class="hljs-comment">// Close the database connection</span>
db.close();
</code></pre><p>The pattern is similar. We define an <code>updateQuery</code> method to <code>UPDATE</code> a record that we'll define. This operation will change the <code>age</code> value for an entry whose name equals <code>Trevor</code>. </p>
<p>You may recall that Trevor's age was earlier listed as 25. We're going to update that to 30. Everything else will work the same as before, including closing the connection when we're done.</p>
<p>This section of code from the third file will delete a record:</p>
<pre><code><span class="hljs-keyword">const</span> deleteQuery = <span class="hljs-string">`DELETE FROM users WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> deletedName = <span class="hljs-string">'name1'</span>;
db.run(deleteQuery, [deletedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Deleted <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});
</code></pre><p>The code above will delete the record where the name equals <code>Trevor</code>.</p>
<p>You can run any of those files using the <code>node</code>  command. But you should first make sure that you've installed the <code>sqlite3</code> module:</p>
<pre><code>$ npm install sqlite3
</code></pre><p>Next I'll use <code>node</code> to run the first file (that you could choose to call <code>db.js</code>). </p>
<pre><code>$ node db.js
Inserted data <span class="hljs-keyword">with</span> id <span class="hljs-number">1</span>
</code></pre><p>We'll see that a new record has been successfully inserted. If you list the directory contents, you'll also see that a new <code>mydatabase.db</code> file has been created.</p>
<p>You can always manually log into sqlite3 to see how things might have changed. I'll reference the <code>mydatabase.db</code> file so we can open it up right away. </p>
<pre><code>$ sqlite3 mydatabase.db
</code></pre><p>Typing <code>.tables</code> within the SQLite interface will list all the existing tables in this database. In our case, it'll be the <code>users</code> table we created. </p>
<pre><code>sqlite&gt; .tables
users
sqlite&gt;
</code></pre><p>Now I'll use the SQL <code>select</code> command to display a record. Here I'll use the asterisk to represent all records and specify the <code>users</code> table. </p>
<pre><code>sqlite&gt; SELECT * FROM users;
<span class="hljs-number">1</span>|Trevor|<span class="hljs-number">25</span>
sqlite&gt;
</code></pre><p>We can see that record <code>1</code> containing <code>Trevor</code> who is 25 years old has been created. Great!</p>
<p>Finally, we can run the <code>delete</code> code which should remove Trevor altogether:</p>
<pre><code><span class="hljs-keyword">const</span> deleteQuery = <span class="hljs-string">`DELETE FROM users WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> deletedName = <span class="hljs-string">'Trevor'</span>;
db.run(deleteQuery, [deletedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Deleted <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});
</code></pre><p>I should note that the <code>db.run</code> and <code>db.close</code> format I used for those methods can also be referred to as <code>Database.run()</code>, and <code>database.close()</code>. It's just a matter of preference - or, in my case, laziness. I'm a Linux admin, after all, and the very best admins are, in principle, lazy.</p>
<h2 id="heading-summary">Summary</h2>
<p>We've seen how use JavaScript to connect to a back end database, create a new table, and then add, modify, and delete records in that table. And we seem to have gotten away with it, too! </p>
<p>Now try this on your own computer. But play around with the values. Even better: build something practical.</p>
<p><em>This article comes from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-web-development-essentials-exam-study-guide/?referralCode=C92570BCBB38302A9257">my Complete LPI Web Development Essentials Study Guide course</a>.</em> <em>And there's much more technology goodness available at <a target="_blank" href="https://bootstrap-it.com/">bootstrap-it.com</a></em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Install MySQL and MySQL Workbench on Windows ]]>
                </title>
                <description>
                    <![CDATA[ If you want to learn MySQL, starting with a good client is super helpful – especially when you are just beginning your journey. There are a lot of clients out there for your MySQL-based needs, like XAMPP, DataGrip, and others. Among all of them, I pr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-install-mysql-workbench-on-windows/</link>
                <guid isPermaLink="false">66b902ea3639976bd84355b9</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MySQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Windows ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Md. Fahim Bin Amin ]]>
                </dc:creator>
                <pubDate>Fri, 30 Jun 2023 18:23:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/boitumelo-phetla-0DJHJcpwN9Q-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you want to learn MySQL, starting with a good client is super helpful – especially when you are just beginning your journey.</p>
<p>There are a lot of clients out there for your MySQL-based needs, like XAMPP, DataGrip, and others. Among all of them, I prefer the <a target="_blank" href="https://www.mysql.com/products/workbench/">MySQL Workbench</a>. It is completely free, by the way.</p>
<p>In this tutorial, I will show you how you can install and configure your Windows machine for this MySQL and MySQL workbench from scratch. </p>
<p>If you enjoy learning from videos as well, then don't worry as I have also created a step-by-step video just for you:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/kZf_h-Phfds" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-install-mysql-workbench">How to Install MySQL Workbench</h2>
<h4 id="heading-download-mysql-workbench">➡️ Download MySQL Workbench</h4>
<p>Make sure to visit only the <a target="_blank" href="https://www.mysql.com/products/workbench/">official website</a> for downloading the MySQL Workbench. You do not want to get into shoddy websites and download the wrong file that infects your favorite machine, right?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>Find the official website for MySQL Workbench: https://www.mysql.com/products/workbench/</em></p>
<p>Now click on the "DOWNLOADS" tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-32_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Scroll down until you find <code>MySQL Community (GPL) Downloads »</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-32_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on <code>MySQL Community (GPL) Downloads »</code>. After that, on the new page, click "MySQL installer for Windows".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-32_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>From the dropdown menu, select your operating system as "Microsoft Windows". Then download the file which is larger in size.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>A <code>.msi</code> file will be downloaded. That is our installer file to install MySQL and MySQL workbench.</p>
<h4 id="heading-install-both-mysql-and-mysql-workbench">➡️ Install both MySQL and MySQL Workbench</h4>
<p>Simply double click on the installer file. It will reload the necessary components and open the installer GUI selection window. Choose the setup type as custom and click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-34_1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Select Custom</em></p>
<p>A new page will appear. Make sure to select the latest "MySQL Server", "MySQL Workbench" and "MySQL Shell". Selecting and clicking on the right side arrow will take the product name in the "Products to be installed section". Then click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-34-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Install necessary components</em></p>
<p>Click "Execute" to install the three necessary components. The process might take some time depending on your internet speed and computer configuration. After it gets finished, simply click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-35.png" alt="Image" width="600" height="400" loading="lazy">
<em>Execute</em></p>
<p>In the Product Configuration window, simply click "Next". It will install the three selected components for us.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-37.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Keep everything as it is and simply click "Next". It will configure the MySQL Server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-37_1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Keep everything as it is and simply click "Next". It will apply the TCP/IP connectivity for our MySQL server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-37_2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Now give it a Root password. For testing purposes, I am using a very simple "1111" as my password, but I would recommend not doing the same. Also, make sure to remember the password as you will need it when you want to work in MySQL Workbench. Click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-37_3.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Keep everything as it is, and simply click "Next". It will make sure to setup our root password for the MySQL workbench.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-38.png" alt="Image" width="600" height="400" loading="lazy">
<em>Root password</em></p>
<p>We want to run the service as a Standard System Account for our operating system. Therefore, keep everything as it is, and simply click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-38_1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Select the option to grant full access to the user running the Windows Service and then click "Next."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-38_2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Then click "Execute". This will grant the full access to the user running the Windows service and the administrator group only, but the other users and groups will not have its access. </p>
<p>So if you have multiple user accounts in your computer, then they will not be able to access the MySQL server/Workbench. If you want then you can change the settings here based on your need.</p>
<p>As I have only one user account in my Windows machine, I can safely keep the first option selected.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-38_3.png" alt="Image" width="600" height="400" loading="lazy">
<em>Execute</em></p>
<p>It might take some time. Then when you will receive a green check box in all configuration steps, simply click "Finish".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-38_4.png" alt="Image" width="600" height="400" loading="lazy">
<em>Finish</em></p>
<p>The configuration has beep applied successfully. Simply click "Next".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-39.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next</em></p>
<p>Click "Finish" to complete the installation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-39_1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Finish</em></p>
<p>It will open the MySQL Workbench and MySQL Shell. Simply close all of them now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-39_1-L.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-configuration">➡️ Configuration</h2>
<p>Now we need to configure the path variables for our operating system. Go to the drive where you have installed your Windows operating system. Like others, I have also installed my operating system on the "C" drive. </p>
<p>Therefore, I am going to the "C" drive and opening the "Program Files" directory.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Go to the "MySQL" folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then go to the MySQL Server folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Go to the "bin" folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Copy the path/address. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40_4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now open the Environment Variables settings. Simply click on the Windows button and type "env". </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-40_5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click "Environment Variables".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Select the "Path" and click "Edit".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-41_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click "New". A new blank box will appear. Paste the path/address that you copied earlier. Do not close the window now as we need to do the same thing for the MySQL Shell folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-41_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we need to do the same thing for the MySQL Shell also. Open the MySQL Shell folder now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-41_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Go to the "bin" folder.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-41_4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Copy the path/directory.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-42.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now apply the same process as you did earlier. Click "New" on the Edit environment variable window. Paste the path/directory in the new blank box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-42_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click "OK".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-42_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click "OK" again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-42_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And click "OK" one more time.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-42_4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-finishing-up">➡️ Finishing Up</h2>
<p>Our task is now finished. You can now open the MySQL Workbench.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Simply click on the Local instance. It will ask for the root password. Enter the password. If you do not want to go into the same hassle of entering a password every time, check the box on save password in the vault. Click "OK".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is your default MySQL Workbench workspace.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43_2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Workbench workspace</em></p>
<p>If you want then you can also hide the SQL Additions tab by clicking on the colored box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>For getting the Schemas, click on the "Schemas" tab from the navigator.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43_4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Your MySQL Workbench is also ready for any kind of development process. You can also use MySQL from your terminal as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_10-43_5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/2023-06-28_11-32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Thank you for reading the entire article.</p>
<p>If you have any questions, feel free to reach out to me using <a target="_blank" href="https://twitter.com/Fahim_FBA">Twitter</a> or <a target="_blank" href="https://www.linkedin.com/in/fahimfba/">LinkedIn</a>.</p>
<p>Also, make sure to follow me on <a target="_blank" href="https://github.com/FahimFBA">GitHub</a>!</p>
<p>You can also <a target="_blank" href="https://www.youtube.com/@FahimAmin?sub_confirmation=1">subscribe to my YouTube channel</a> for more helpful video content.</p>
<p>If you are interested then you can also check my website: <a target="_blank" href="https://fahimbinamin.com/">https://fahimbinamin.com/</a></p>
<p>Have a great day! 😊</p>
<p>Cover: Photo by <a target="_blank" href="https://unsplash.com/@writecodenow?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Boitumelo Phetla</a> on <a target="_blank" href="https://unsplash.com/photos/0DJHJcpwN9Q?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
