2015-09-04 16 views
5

ich suche nach einer Lösung durch Active Record die hierarchischen Daten in einzelner Abfrage zu erhalten.Gewinde Daten in Yii2

Was ich jetzt mache zuerst alle Daten zu holen und dann auf die gewünschte Array mit einer rekursiven Funktion Umwandlung Array.

$allUsers = User::find() 
     ->asArray() 
     ->all(); 
$arr = Yii::$app->TreeComponent->getUserChildren($allUsers, $userId, $userId); 

und in TreeComponent

public function getUserChildren($src_arr, $currentId, $userId, $parentFound = false) 
{ 
    $cats = array(); 
    foreach ($src_arr as $row) { 
     if ($row['id'] == $userId) { 
      $row['parent'] = ""; 
     } 
     if ((!$parentFound && $row['id'] == $currentId) || $row['parent'] == $currentId) { 
      $rowData = array(); 
      foreach ($row as $k => $v) 
       $rowData[$k] = $v; 
      $cats[] = $rowData; 
      if ($row['parent'] == $currentId) { 
       $cats = array_merge($cats, $this->fetchRecursive($src_arr, $row['id'], true)); 
      } 
     } 
    } 
    return $cats; 
} 

Seine adaequat. Aber vor kurzem gehe ich durch CakePHP 's find('threaded'), ich denke, es wird rekursive Funktion Ausführungszeit und weniger Code speichern.

Ich bin neugierig, ob es eine Funktion gibt in Active Record auch.

+2

Es gibt keine Funktion dafür, aber Sie könnten [verschachtelte Listen] (https://github.com/creocoder/yii2-nested-sets) verwenden. – Beowulfenator

+1

Yi's AR kann hierarchische Daten in einem einzigen Aufruf nicht füllen. Sie können eine baumartige Arraystruktur mithilfe von Referenzen erstellen, um Rekursionen zu vermeiden. Wenn Sie daran interessiert sind, kann ich ein Beispiel veröffentlichen. – nineinchnick

+0

@nineinchnick ja bitte ich möchte das Beispiel sehen. – ankitr

Antwort

2

In Yii2 gibt es keine solche Funktionalität. CakePHP führt auch mehrere Abfragen im Hintergrund aus und wickelt sie einfach in einen Multithread-Aufruf ein. Der Hauptgeschwindigkeitsvorteil, den Sie erzielen würden, wenn Sie tatsächlich nur eine einzelne Abfrage durchführen könnten.

Es gibt zwei Möglichkeiten, dies zu erreichen:

  • Ihren Weg ... Abrufen alles und führen Sie sie in Ihrem Code
  • NestedSet Muster wie oben
  • in einem Kommentar erwähnt

NestedSet

Für Yii2 gibt es eine sehr gute Erweiterung, die das verschachtelte Mengenmuster implementiert. Sie können es hier finden:

https://github.com/creocoder/yii2-nested-sets

Vor- und Nachteile

Der Vorteil ist - natürlich -, dass man alles mit einer einzigen Abfrage holen kann. Sie können sogar mehrere Bäume in einer Tabelle speichern.

Der Hauptnachteil ist Sortierspalten entsprechend, während immer noch die Baumstruktur beibehalten wird. Der verschachtelte Satz ist mit zwei Attributen organisiert: links und rechts. Das bedeutet, dass alle Daten nach diesen beiden Attributen sortiert sind. Um eine Baumstruktur zu erhalten, die zB nach Namen sortiert ist, müssen Sie noch eine codeseitige Funktionalität implementieren, um den empfangenen Datensatz nach der Abfrage zu ändern. Der sauberste Weg, um die Daten zu sortieren beim Speichern ... einen neuen Datensatz nach seiner Stelle einfügen Bedeutung in Ihrem

Wikipedia hat eine sehr gute explenation des verschachtelten Satzes Sortierung gewünscht: https://en.wikipedia.org/wiki/Nested_set_model

Diese Abbildung zeigt so funktioniert es:

NestedSet illustration

Beispiel: ‚Hosen‘ und ‚Jacken‘ Kinder ‚Anzüge‘ sind, da beide ihre linke und rechte Attribute sind zwischen dem linken (3) und rechts (8) Wert von ' Anzüge ". Wenn Sie ein Kind zu 'Jacken' hinzufügen wollten, würden Sie es zwischen 6 und 7 injizieren ... und daher alle Werte höher oder gleich 7 um zwei erhöhen. Das neu injizierte Kind von "Jacken" würde dann einen linken Wert von 7 und einen rechten Wert von 8 erhalten.

Wie Sie sehen können, können Sie jetzt ganz einfach einen ganzen (Teil-) Baum durch einfaches Filtern der linken und rechten Attribute abrufen. Ich f Sie alles von Klagen "nach unten Ihre Frage wollte würde wie folgt aussehen:

SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC 

abschließende Antwort auf Ihre Frage

Wenn Ihr Schwerpunkt Komfort

No. Es gibt keine solche Funktionalität. Wenn Sie immer noch einen regulären Baum in Ihrer Datenbank haben wollen und sich nur nicht um die Zusammenführung der Daten kümmern wollen, müssten Sie eine ähnliche Funktionalität für CakePHPs Methoden schreiben. Das sollte ziemlich einfach sein und ich denke, dass sich viele Leute dafür interessieren würden.

Wenn Ihr Hauptanliegen ist die Geschwindigkeit

Verwenden Sie den verschachtelten Satz. Es ist ein höllisches Muster und sooo stark!

+0

Danke für die Antwort @ PLM57. Mein Hauptanliegen ist Geschwindigkeit, da es Tausende von Datensätzen gibt. Und in meinem Fall kann es mehr als 2 Kind eines Knotens geben, wenn verschachtelte Menge wird immer noch gültige Ansatz? – ankitr

+0

Gern geschehen! Ja, Sie können so viele Kinder pro Knoten haben, wie Sie möchten! Es ist nicht wie ein Binärbaum, wo nur zwei Kinder erlaubt sind ... es ist ein regulärer Baum, aber anders organisiert (mit Links/Rechts-Attributen anstelle einer Eltern-ID). Diese Illustration im Wiki-Artikel erklärt es sehr gut: https://en.wikipedia.org/wiki/Nested_set_model#/media/File:NestedSetModel.svg – PLM57

0

Hier ist eine andere Möglichkeit, einen Baum zu speichern und ohne Rekursion zu holen. Es benötigt 2 Tabellen.

tree_data 

    Column | Type |           
-----------+---------+ 
id  | integer | 
parent_id | integer | 
level  | integer | 
sort  | integer | 


tree_structure 

Column | Type |       
--------+---------+ 
parent | integer | 
child | integer | 

Beispiel:

select * from tree_data; 

id | parent_id | level | sort 
----+-----------+-------+------ 
    1 |   0 |  0 | 1000 
    2 |   1 |  1 | 1000 
    3 |   1 |  1 | 2000 
    4 |   1 |  1 | 1500 
    5 |   1 |  1 | 1750 
    6 |   5 |  2 | 1000 


select * from tree_structure order by parent, child; 

parent | child 
--------+------- 
     1 |  1 
     1 |  2 
     1 |  3 
     1 |  4 
     1 |  5 
     1 |  6 
     2 |  2 
     3 |  3 
     4 |  4 
     5 |  5 
     5 |  6 
     6 |  6 

Der resultierende Baum:

├── 1 
│ ├── 2 
│ ├── 4 
│ ├── 5 
│  ├── 6 
│ ├── 3 

den Baum abzufragen:

SELECT tree_data.* 
FROM tree_data 
INNER JOIN tree_structure ON tree_data.id = tree_structure.child and tree_structure.parent = 1 
ORDER BY level, sort; 

Hier ist eine Reihe von Klassen für yii2 to manage this ree