Skip to main content
Databases · lesson 1 of 6
Databases intermediate Lesson 1 of 6

Choosing a Database: A Decision Framework With Real Numbers

"It depends" is true and useless. A weighted scoring framework — consistency, query flexibility, write latency, schema flexibility — run against three real scenarios to three different, honest winners.

By SkillByExample · Updated

databases postgresql mongodb redis architecture

“It depends” is true and useless. What makes it useful is naming what it depends on, putting a number on it, and running the same scoresheet against a real scenario instead of a generic one — the same approach the cloud track uses to choose between AWS, Azure, and GCP, applied here to choosing between database engines.

Four factors, scored once

# choose_database.py
def recommend(name, weights, scores):
    engines = ("PostgreSQL", "MongoDB", "Redis")
    totals = {e: sum(w * scores[f][e] for f, w in weights.items()) for e in engines}
    ranked = sorted(totals.items(), key=lambda kv: -kv[1])
    print(name)
    for engine, total in ranked:
        print(f"  {engine:<11}{total:5.2f}")
    print(f"  -> recommend {ranked[0][0]}\n")


SCORES = {
    "consistency":        {"PostgreSQL": 9, "MongoDB": 7, "Redis": 3},
    "query_flexibility":  {"PostgreSQL": 9, "MongoDB": 7, "Redis": 2},
    "write_latency":      {"PostgreSQL": 6, "MongoDB": 7, "Redis": 10},
    "schema_flexibility": {"PostgreSQL": 6, "MongoDB": 9, "Redis": 7},
}

Each engine gets one 0-10 score per factor, scored once, reused across every scenario — only the weights change per scenario, because the weights are where the actual judgment about a specific workload lives.

Three scenarios, three honest winners

recommend(
    "E-commerce order system",
    {"consistency": 0.45, "query_flexibility": 0.25, "write_latency": 0.10, "schema_flexibility": 0.20},
    SCORES,
)
recommend(
    "Real-time game leaderboard",
    {"consistency": 0.10, "query_flexibility": 0.05, "write_latency": 0.65, "schema_flexibility": 0.20},
    SCORES,
)
recommend(
    "Content catalog, evolving schema",
    {"consistency": 0.10, "query_flexibility": 0.30, "write_latency": 0.10, "schema_flexibility": 0.50},
    SCORES,
)
$ python choose_database.py
E-commerce order system
  PostgreSQL  8.10
  MongoDB     7.40
  Redis       4.25
  -> recommend PostgreSQL

Real-time game leaderboard
  Redis       8.30
  MongoDB     7.40
  PostgreSQL  6.45
  -> recommend Redis

Content catalog, evolving schema
  MongoDB     8.00
  PostgreSQL  7.20
  Redis       5.40
  -> recommend MongoDB

Same three engines, same four scores per engine — three different winners, each one following directly from what that scenario actually weighted.

Reading the leaderboard result closely

Redis loses badly on 3 of 4 factors in every single scenario — its query_flexibility score of 2 is the lowest number in the whole table. It still wins the leaderboard scenario outright because that scenario puts 0.65 of the total weight — nearly two-thirds — on write_latency, where Redis scores a 10 against Postgres’s 6. The framework doesn’t average a database’s weaknesses away; a large enough weight on one real strength is enough to win on its own.

Reading the content-catalog result closely

This is the one worth sitting with, because a common assumption — “flexible schema always means MongoDB” — turns out to be conditional on how much weight schema flexibility actually gets. At 0.50, MongoDB’s schema_flexibility score of 9 (against PostgreSQL’s 6, since JSONB adds flexibility to a fundamentally table-shaped model rather than replacing it) is enough to overcome PostgreSQL’s higher scores on the other three factors combined. Drop that weight to 0.20 — the same weight used in the e-commerce scenario — and PostgreSQL wins this scenario too, because the deciding factor no longer decides.

Why this beats “it depends”

None of the three engines’ own documentation can honestly run this comparison — each project’s docs are written to make that project look good, not to fairly score a competitor. That’s the gap this framework fills: the same four factors, scored once, reused against whatever weights actually describe your workload.

Practice

1. Add a fourth engine, MySQL, with its own scores, and re-run the e-commerce scenario.
SCORES["consistency"]["MySQL"] = 8
SCORES["query_flexibility"]["MySQL"] = 8
SCORES["write_latency"]["MySQL"] = 7
SCORES["schema_flexibility"]["MySQL"] = 5

def recommend(name, weights, scores):
    engines = ("PostgreSQL", "MongoDB", "Redis", "MySQL")
    totals = {e: sum(w * scores[f][e] for f, w in weights.items()) for e in engines}
    ranked = sorted(totals.items(), key=lambda kv: -kv[1])
    print(name)
    for engine, total in ranked:
        print(f"  {engine:<11}{total:5.2f}")
E-commerce order system
  PostgreSQL  8.10
  MongoDB     7.40
  MySQL       7.30
  Redis       4.25

recommend() was written generically over the engine dict, so adding a fourth engine needed no change to the scoring logic — only one more key in SCORES and the engines tuple.

2. Add a fifth factor, "operational maturity," and give it real weight in the e-commerce scenario.
SCORES["operational_maturity"] = {"PostgreSQL": 9, "MongoDB": 7, "Redis": 8}
weights = {"consistency": 0.35, "query_flexibility": 0.20, "write_latency": 0.10,
           "schema_flexibility": 0.15, "operational_maturity": 0.20}

Re-running with this fifth factor keeps PostgreSQL on top for this scenario — its already strong scores are reinforced rather than contradicted — but the exact margin changes, which is the point of scoring instead of guessing: you can see how sensitive a recommendation is to a factor you just added.

3. Set every weight equal (0.25 each) for all three scenarios and compare.

Equal weights erase the scenario-specific reasoning entirely — the leaderboard scenario and the e-commerce scenario would get scored identically, which throws away exactly the judgment call (“what does this workload actually need”) that makes the framework useful in the first place.

4. Score your own current project's database choice against these four factors.

Write down honest 0-10 scores for the engines you’re actually choosing between, and weights that reflect what genuinely matters for that project — not what you’d like to matter. A result that disagrees with your gut is worth investigating before you commit to it.

Next: transactions across engines — which of these can actually roll back a partial failure, and which can’t.

Frequently Asked Questions

Is PostgreSQL, MongoDB, or Redis "the best" database?
None of them, in general — the honest answer depends on what a specific workload actually needs. This lesson's own three scenarios each pick a different winner using the same four factors, just weighted differently, which is the whole point: the framework surfaces what you're actually trading off instead of settling it with a preference.
Why did MongoDB win the "evolving schema" scenario even though PostgreSQL scored higher on two of the four factors?
Because that scenario weighted schema_flexibility at 0.50 — half the entire decision — and MongoDB's native document model scores highest on exactly that factor (9 vs PostgreSQL's 6, since JSONB adds flexibility to a fundamentally rigid schema rather than replacing it). A high score on a low-weighted factor doesn't move the total nearly as much as a high score on the deciding one.
Redis scored lowest on 3 of 4 factors in every scenario — why does it ever win?
It wins the leaderboard scenario specifically because that scenario weights write_latency at 0.65 — nearly two-thirds of the whole decision — and Redis's in-memory model scores a 10 there against Postgres's 6 and MongoDB's 7. The framework doesn't average away a database's weaknesses; a large enough weight on its one real strength is enough to win outright.
Can this same framework be extended to more than three engines or more than four factors?
Yes — the recommend() function is generic over both; scores and weights are just dictionaries. Adding a fourth engine or a fifth factor (e.g. operational maturity, hosting cost) means adding one more key to each dictionary, with no change to the scoring logic itself.
Why don't official database docs (Postgres's, MongoDB's, Redis's) publish this kind of comparison?
The same reason a cloud vendor's docs won't score AWS below Azure for a given scenario: each project's documentation is written to make its own database look good, not to fairly score a competitor. A framework like this only works run by someone with no stake in the outcome, against the actual constraints of one specific workload.