【问题标题】:Laravel ORM from self referencing table get N level hierarchy JSON来自自引用表的 Laravel ORM 获取 N 级层次结构 JSON
【发布时间】:2014-08-31 14:20:16
【问题描述】:

我正在使用LARAVEL 4MySQL 后端。

我有一个self-referencing 表,其中包含id, name, typeparent 列。 这里,parentId 列的foreign-key。表中数据如下:

id  name          type         parent 
1   General       group        NULL
2   What is..?    question     1
3   aa            answer       2
4   bb            answer       2
5   cc            answer       2
6   How is..?     question     1
7   ba            answer       6
8   bb            answer       6
9   Where is..?   question     4
10  ca            answer       9
11  cb            answer       9
12  Who is..?     question     6
13  da            answer       12
14  db            answer       12
15  Specific      group        NULL
16  When is..?    question     15
17  ea            answer       16
18  eb            answer       16
19  Whome is..?   question     2
20  fa            answer       19
21  fb            answer       19
22  fc            answer       19

我想要一个使用此关系数据返回 nested JSON 的函数。例如:

[{
  "id" : 1, 
  "name" : "Geneal", 
  "type" : "group", 
  "children" : [{
      "id" : 2, 
      "name" : "What is..?", 
      "type" : "question", 
      "children" : [{
         "id" : 3, 
         "name" : "aa", 
         "type" : "answer"
      },
      {
         "id" : 4, 
         "name" : "bb", 
         "type" : "answer"
      },
      {
         "id" : 5, 
         "name" : "cc", 
         "type" : "answer"
      }]},
      {
      "id" : 6, 
      "name" : "How is..?", 
      "type" : "question", 
      "children" : [{
         "id" : 7, 
         "name" : "ba", 
         "type" : "answer"
      },
      {
         "id" : 8, 
         "name" : "bb", 
         "type" : "answer"
      }]
   }]
... and so on
}]

我创建了一个名为Surveymodel,如下所示:

class Survey extends BaseModel{

    protected $table = 'questions';
    protected $softDelete = false;

    public function parent()
    {
        return $this->belongsTo('Survey', 'parent');
    }

    public function children()
    {
        return $this->hasMany('Survey', 'parent');
    }   
}

并在controller 中调用它:

$user = Survey::all();
$parent = $user->parent()->first();
$children = $user->children()->get();

但我没有得到正确的结果,正如我在上面的JSON 中提到的那样。

print_r($parent->toJson()); 

仅提供具有一级层次结构的记录(即组和问题,而不是答案)。

同时

print_r($children ->toJson());

只提供问题(不提供组和答案)。

我想要整个具有 N 层级的嵌套 JSON 格式的自引用数据

我也试过了

$user = Survey::with('parent', 'children')->get();

但发现与上面的 $parent 相同。

有没有我可以得到想要的结果?

提前谢谢..

【问题讨论】:

  • 我认为 LARAVEL 是无用的框架。我在其文档本身的任何地方都找不到任何帮助。
  • 我认为现在在 stackoverflow 上没有 LARAVEL 的专家
  • 检查这个:github.com/etrepat/baum
  • 阅读文档laravel.com/docs/eloquent#eager-loading嵌套关系,尝试一下,如果仍然需要帮助,请回来。
  • @deczo 我已经在我的问题中提到我使用了急切加载。请参阅 $user = Survey::with('parent', 'children')->get();此语句仅检索组和问题,而不是答案。我希望它作为嵌套数组或具有 N 级的 JSON。如何实现?

标签: php laravel laravel-4


【解决方案1】:

这么简单!!!

1- 在模型中的“子”关系中加载“子”关系,如下所示:

class Survey extends BaseModel{

    protected $table = 'questions';
    protected $softDelete = false;

    public function parent()
    {
        return $this->belongsTo('Survey', 'parent');
    }

    public function children()
    {
       // change this: return $this->hasMany('Survey', 'parent');

        return $this->hasMany('Survey', 'parent')->with('children);
    }   
}

2- 你只需要像这样向你的关系添加 clouser 函数:

$surveys = Survey::with(['children' => function($q) {
            $q->with('children');
       },
       'parent' => function($q) {
            $q->with('parent');
       });

然后您可以像这样访问结果中的嵌套子级:

$surveys->children

无限嵌套:

$surveys->children->first()->children

等等。

【讨论】:

    【解决方案2】:

    以下是手动检索嵌套关系的方法:

    $collection = Model::with('relation1.relation2.relation3')->get();
    

    所以你的情况是:

    $surveys = Survey::with('children.children.children')->get();
    

    显然,当关系固定时,这将完成这项工作,但它不是为同一个表建立递归关系的方法。

    幸运的是,你可以让这种关系递归,那么你只需要检索整棵树:

    $surveys = Survey::with('childrenRecursive');
    

    但是,我不会以这种方式为每一行加载父级。

    这就是你所需要的:

    // Survey model
    // loads only direct children - 1 level
    public function children()
    {
       return $this->hasMany('Survey', 'parent');
    }
    
    // recursive, loads all descendants
    public function childrenRecursive()
    {
       return $this->children()->with('childrenRecursive');
       // which is equivalent to:
       // return $this->hasMany('Survey', 'parent')->with('childrenRecursive);
    }
    
    // parent
    public function parent()
    {
       return $this->belongsTo('Survey','parent');
    }
    
    // all ascendants
    public function parentRecursive()
    {
       return $this->parent()->with('parentRecursive');
    }
    

    编辑:要获得真正的树结构,第一个查询必须仅限于根节点:

    $surveys = Survey::with('childrenRecursive')->whereNull('parent')->get();
    

    【讨论】:

    • 感谢您的回答。不幸的是,我在这个实现中遇到了性能问题。我在这个表中只有 1047 条记录,仍然需要很长时间才能加载这些数据(差不多 10 分钟,当然我有配置好的电脑。)。此表中可能有数千条记录。在那种情况下,我认为它不会起作用。您有任何提高性能的解决方案吗?
    • 我不认为它给了我任何表格数组。递归一定有一些错误。我得到了 181415 行的调用 $surveys = Survey::with('childrenRecursive');但这些都没有表格的任何字段。
    • 它给出了正确的结果,也许你只是用 18 万个项目数组耗尽了你的内存。尝试合理的限制。
    • 好的。它可能会给出正确的结果,但如果它产生性能问题,我将无法使用它。如果你知道有什么技巧可以克服这个问题吗?我是 php 新手,尤其是 laravel。
    • 将 200 000 行加载到数组中总是会导致内存问题。分块处理,分页或其他。如果我不知道您如何处理这些数据,我无法提出建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2014-07-23
    相关资源
    最近更新 更多