CouchDB
hierarchical comments
ranking system
Hacker News style
databases

CouchDB - hierarchical comments with ranking. Hacker News style

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A Hacker News style comment system has two separate requirements: hierarchy and ranking. Hierarchy means comments can reply to comments, creating a tree. Ranking means siblings under the same parent are usually shown in score order rather than pure creation order. CouchDB can support this, but you have to model the tree and the ranking fields deliberately because CouchDB does not do recursive joins for you.

Model Each Comment as Its Own Document

A practical CouchDB design stores one document per comment and includes enough fields to rebuild the thread.

json
1{
2  "_id": "comment:123",
3  "type": "comment",
4  "post_id": "post:42",
5  "parent_id": "comment:100",
6  "root_post_id": "post:42",
7  "author": "alice",
8  "body": "I agree with this approach.",
9  "score": 17,
10  "created_at": "2025-09-23T12:00:00Z",
11  "path": ["comment:100", "comment:123"]
12}

The important fields are:

  • 'post_id or root_post_id to identify the discussion thread'
  • 'parent_id to rebuild direct parent-child relationships'
  • 'score for ranking among siblings'
  • 'path if you want a precomputed ancestry trail'

This avoids expensive graph reconstruction logic later.

Separate the Tree From the Ranking

It is tempting to think score alone is enough, but a comment tree has two ordering problems:

  • which comments belong under which parent
  • in what order siblings under the same parent should appear

Those are different questions.

A simple way to support both is to query comments by thread and then build the tree in application code, using parent_id for attachment and score plus created_at for sibling ordering.

A Useful View Design

One common CouchDB view strategy is to emit comments by thread.

javascript
1function (doc) {
2  if (doc.type === 'comment' && doc.root_post_id) {
3    emit([doc.root_post_id, doc.parent_id || null, -doc.score, doc.created_at], {
4      id: doc._id,
5      parent_id: doc.parent_id,
6      body: doc.body,
7      author: doc.author,
8      score: doc.score,
9      created_at: doc.created_at
10    });
11  }
12}

The compound key does useful work:

  • thread grouping by root_post_id
  • sibling grouping by parent_id
  • descending score through -doc.score
  • stable fallback ordering by created_at

You then fetch all comments for one thread and reconstruct the nested tree in the application layer.

Rebuild the Tree in Application Code

CouchDB is good at document retrieval and sorted view output. Tree assembly is usually easier in application code.

javascript
1function buildTree(comments) {
2  const byId = new Map();
3  const roots = [];
4
5  comments.forEach(comment => {
6    byId.set(comment.id, { ...comment, children: [] });
7  });
8
9  comments.forEach(comment => {
10    const node = byId.get(comment.id);
11    if (comment.parent_id && byId.has(comment.parent_id)) {
12      byId.get(comment.parent_id).children.push(node);
13    } else {
14      roots.push(node);
15    }
16  });
17
18  return roots;
19}

This is often simpler than trying to force the tree shape entirely into the database layer.

Ranking Strategy Choices

Hacker News style ranking can mean different things:

  • direct vote score
  • score plus age decay
  • separate sort for top-level comments and replies

If you use age-decayed ranking, consider storing a materialized rank field that gets recomputed when votes change or on a scheduled basis. CouchDB views sort by stored key values efficiently, but computing complex ranking formulas at query time is less attractive than precomputing what the UI needs.

Common Pitfalls

The most common mistake is expecting CouchDB to return a nested comment tree directly. CouchDB returns documents and sorted view rows, not recursive joined structures.

Another issue is trying to use one field to represent both parent-child structure and ranking. Keep hierarchy fields and ordering fields separate.

Developers also often under-model the ancestry information. A parent_id is usually enough for direct tree reconstruction, but a stored path can help with moderation, deletion, or depth-based UI behavior.

Finally, do not overcomplicate ranking early. Start with sibling sorting by score and stable tie-breaking, then add time decay only if the product actually needs it.

Summary

  • Store each comment as a document with parent_id, thread identity, and ranking fields.
  • Use CouchDB views to fetch comments in a useful order, not to build the nested tree directly.
  • Reconstruct the thread hierarchy in application code.
  • Keep hierarchy concerns separate from ranking concerns.
  • Precompute ranking fields when the sort logic becomes more complex than a simple score.

Course illustration
Course illustration

All Rights Reserved.