1

I have in my database a table similar to this one:

+----+--------+-----------------+
| id | parent | name            |
+----+--------+-----------------+
| 1  | 0      | father 1        |
| 2  | 0      | father 2        |
| 3  | 1      | child 1 - 3     |
| 4  | 0      | father 4        |
| 5  | 2      | child 2 - 5     |
| 6  | 2      | child 2 - 6     |
| 7  | 1      | child 1 - 7     |
+----+--------+-----------------+

The list is purposedly only sorted by the primary key (id). The logic is simple, if the parent is 0, then it's a father category, otherwise is a child or child-child (and so on).

Using Ruby (Sinatra and DataMapper), I want to achieve this cascaded list:

[
   {
      "id":1,
      "parent":0,
      "name":"father 1",
      "childs":[
         {
            "id":3,
            "parent":1,
            "name":"child 1 - 3",
            "childs":[ ]
         },
         {
            "id":7,
            "parent":1,
            "name":"child 1 - 7",
            "childs":[ ]
         }
      ]
   },
   {
      "id":2,
      "parent":0,
      "name":"father 2",
      "childs":[
         {
            "id":5,
            "parent":1,
            "name":"child 2 - 5",
            "childs":[ ]
         },
         {
            "id":7,
            "parent":1,
            "name":"child 2 - 6",
            "childs":[ ]
         }
      ]
   },
   {
      "id":4,
      "parent":0,
      "name":"father 4",
      "childs":[ ]
   }
]

I've created the Category class as follows...

class Category
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :length => 2..50, :required => true
  property :parent, Integer, :default => 0
  # All categories may have sub-categories
  has n, :childs, 'Category', :parent_key => :id, :child_key => :parent, :constraint => :protect
end

And I'm obtaining the parent list by asking for parents only to the database:

{ :data => Category.all(:parent => 0, :order => [ :name.asc ]), :total => Category.count(:parent=>0) }.to_json

But I can't manage to get the list of childs for each category.

I could create a recursive "each -> Category.all" query but that would end in a lot of queries for a table with just 100s rows (one per each parent, one per each child, etc) instead of just a couple ones. I could cache the list if there's not a better way to do this.

How can I automatically load and merge in cascade all the childs for each parent and each child (categories, may have sub-categories) without a lot of queries?

kuteninja
  • 23
  • 4
  • BTW, it's possible to change the database, it's a new project so I'm not forced to use it as is. – kuteninja Nov 06 '14 at 15:32
  • The other idea that I came up with was to do a Category.all where parent is not 0, and then manually correlate each by pushing into it's parent childs associations, but I'm sure there must be an "ORM" way to do this – kuteninja Nov 06 '14 at 19:20

0 Answers0