Retrieve all parent/child records from database on Laravel (hierarchical data)

后端 未结 1 1572
误落风尘
误落风尘 2021-02-04 17:26

I have the following simplified database table structure for a legacy tickets-like system.

messages
  id         INT
  parent_id  INT
  content    TEXT
  answer          


        
相关标签:
1条回答
  • 2021-02-04 18:30

    Since you are doing hierarchical operations, you should use a strategy to save and retrieve this data from your database.

    One approach is to use Nested Set Model, that can make it easier. Laravel has a great package that deals with it, called etrepat/baum, that also explains how it works and I quote:

    The theory behind, a TL;DR version

    An easy way to visualize how a nested set works is to think of a parent entity surrounding all of its children, and its parent surrounding it, etc. So this tree:

    root
      |_ Child 1
        |_ Child 1.1
        |_ Child 1.2
      |_ Child 2
        |_ Child 2.1
        |_ Child 2.2
    

    Could be visualized like this:

     ___________________________________________________________________
    |  Root                                                             |
    |    ____________________________    ____________________________   |
    |   |  Child 1                  |   |  Child 2                  |   |
    |   |   __________   _________  |   |   __________   _________  |   |
    |   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |
    1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14
    |   |___________________________|   |___________________________|   |
    |___________________________________________________________________|
    

    The numbers represent the left and right boundaries. The table then might look like this:

    id | parent_id | lft  | rgt  | depth | data
     1 |           |    1 |   14 |     0 | root
     2 |         1 |    2 |    7 |     1 | Child 1
     3 |         2 |    3 |    4 |     2 | Child 1.1
     4 |         2 |    5 |    6 |     2 | Child 1.2
     5 |         1 |    8 |   13 |     1 | Child 2
     6 |         5 |    9 |   10 |     2 | Child 2.1
     7 |         5 |   11 |   12 |     2 | Child 2.2
    

    To get all children of a parent node, you

    SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
    

    To get the number of children, it's

    (right - left - 1)/2
    

    To get a node and all its ancestors going back to the root, you

    SELECT * WHERE node.lft IS BETWEEN lft AND rgt
    

    As you can see, queries that would be recursive and prohibitively slow on ordinary trees are suddenly quite fast. Nifty, isn't it?

    0 讨论(0)
提交回复
热议问题