11

I'm trying to implement a basic way of displaying comments in the way that Hacker News provides, using CouchDB. Not only ordered hierarchically, but also, each level of the tree should be ordered by a "points" variable.

The idea is that I want a view to return it in the order I except, and not make many Ajax calls for example, to retrieve them and make them look like they're ordered correctly.

This is what I got so far:

  • Each document is a "comment".
  • Each comment has a property path which is an ordered list containing all its parents.

So for example, imagine I have 4 comments (with _id 1, 2, 3 and 4). Comment 2 is children of 1, comment 3 is children of 2, and comment 4 is also children of 1. This is what the data would look like:

{ _id: 1, path: ["1"] },
{ _id: 2, path: ["1", "2"] },
{ _id: 3, path: ["1", "2", "3"] }
{ _id: 4, path: ["1", "4"] }

This works quite well for the hierarchy. A simple view will already return things ordered the way I want it.

The issue comes when I want to order each "level" of the tree independently. So for example documents 2 and 4 belong to the same branch, but are ordered, on that level, by their ID. Instead I want them ordered based on a "points" variable that I want to add to the path - but can't seem to understand where I could be adding this variable for it to work the way I want it.

Is there a way to do this? Consider that the "points" variable will change in time.

Octavian Helm
  • 39,405
  • 19
  • 98
  • 102
Luca Matteis
  • 29,161
  • 19
  • 114
  • 169
  • Hi, Luca. Are you willing to update the comments in a big sweep? For example, every hour, increment their age? The answer to that question affects the answer to the problem. Thanks! – JasonSmith May 14 '12 at 11:06
  • Hi @JasonSmith. For now we can forget the date issue. Let's imagine each "comment" has a `score` property that contains an integer value of its score. The display would need to not only show the hierarchy as explained above, but also order each "level" of the tree based upon this `score` property. This is where I'm having issues. You can see an example here of what I'm trying to achieve: http://hckr.iriscou.ch/news/_design/news/_view/items The first being the root comment, and the rest children, and children of children. The key contains the path and also the `score` value as last element. – Luca Matteis May 14 '12 at 11:08
  • However, as you can see, this isn't working because the second last element of the keys is the _id of actual document. This is needed so that I can attach in order its children (based on the path logic). I hope this makes sense. In any case, keeping the score as last value isn't working :( – Luca Matteis May 14 '12 at 11:12

2 Answers2

4

Because each level needs to be sorted recursively by score, Couch needs to know the score of each parent to make this work the way you want it to.

Taking your example with the following scores (1: 10, 2: 10, 3: 10, 4: 20)

In this case you'd want the ordering to come out like the following:

.1
.1.4
.1.2
.1.2.3

Your document needs a scores array like this:

{ _id: 1, path: [1], scores: [10] },
{ _id: 2, path: [1, 2], scores: [10,10] },
{ _id: 3, path: [1, 2, 3], scores: [10,10,10] },
{ _id: 4, path: [1, 4], scores: [10,20] }

Then you'll use the following sort key in your view.

emit([doc.scores, doc.path], doc)

The path gets used as a tiebreaker because there will be cases where sibling comments have the exact same score. Without the tiebreaker, their descendants could lose their grouping (by chain of ancestry).

Note: This approach will return scores from low-to-high, whereas you probably want scores (high to low) and path/tiebreaker(low to high). So a workaround for this would be to populate the scores array with the inverse of each score like this:

{ _id: 1, path: [1], scores: [0.1] },
{ _id: 2, path: [1, 2], scores: [0.1,0.1] },
{ _id: 3, path: [1, 2, 3], scores: [0.1,0.1,0.1] },
{ _id: 4, path: [1, 4], scores: [0.1,0.2] }

and then use descending=true when you request the view.

Peter Dixon-Moses
  • 3,169
  • 14
  • 18
  • Also if you're going to use numeric post ids, your path should contain unquoted values so you don't get alphabetic sorting behavior (e.g. 1, 10, 2, 3, 4, 5, 6, 7, 8, 9). – Peter Dixon-Moses May 23 '12 at 18:44
  • Interesting. However this requires me to update all the children scores when a score has changed. Thanks I guess it's a possible solution. I decided to let the client do the work of ordering hierarchically instead of Couch. – Luca Matteis May 25 '12 at 08:32
  • Yep that's probably the easiest way. – Peter Dixon-Moses May 26 '12 at 03:33
2

Maybe anybody interestingly the thread on this question with variants of solutions:

http://mail-archives.apache.org/mod_mbox/couchdb-dev/201205.mbox/thread -> theme "Hierarchical comments Hacker News style" 16/05/2012