7

PostgreSQL の ltree モジュールを使用して、このマテリアライズド パス ツリー構造を構築しました。

  • id1
  • id1.id2
  • id1.id2.id3
  • id1.id2.id5
  • id1.id2.id3.id4 ...など

もちろん、ltree を使用して、ツリー全体または特定のパス/サブパスからすべてのノードを簡単に取得できますが、そうすると、当然、多くの行が得られます (これは、ノードの配列/スライスに相当します)。終了.. Golang/使用するプログラミング言語)

私が求めているのは、ツリーを取得することです-理想的には特定の開始および終了パス/ポイントから-etcのような階層的なJSONツリーオブジェクトとして

{
  "id": 1,
  "path": "1",
  "name": "root",
  "children": [
    {
      "id": 2,
      "path": "1.2",
      "name": "Node 2",
      "children": [
        {
          "id": 3,
          "path": "1.2.3",
          "name": "Node 3",
          "children": [
            {
              "id": 4,
              "path": "1.2.3.4",
              "name": "Node 4",
              "children": [

              ]
            }
          ]
        },
        {
          "id": 5,
          "path": "1.2.5",
          "name": "Node 5",
          "children": [

          ]
        }
      ]
    }
  ]
}

線形(非階層)行/配列/スライスの結果セットから、もちろんGolangでパスを展開し、必要なビジネスロジックを作成してこのjsonを作成できることを知っていますが、便利なこれを PostgreSQL で直接実現する方法。

では、PostgreSQL で ltree ツリー構造を json にどのように出力しますか?

ltree がわからない場合は、質問を「具体化されたパス ツリーから階層 json へ」に一般化できると思います。

また、ltreeパスに加えて、すべてのノードにparent_idを追加するという考えで遊んでいます.親IDの変更がいつ発生したかに基づいてパスを管理する(更新し続ける)ために、そのparent_idにトリガーを置くことを考えました-それは別の質問だと思いますが、おそらくこれについてあなたの意見も教えてもらえますか?

天才がこれを手伝ってくれることを願っています。:)

便宜上、時間を節約するために使用できる作成スクリプトのサンプルを次に示します。

CREATE TABLE node
(
  id bigserial NOT NULL,
  path ltree NOT NULL,
  name character varying(255),
  CONSTRAINT node_pkey PRIMARY KEY (id)
);

INSERT INTO node (path,name) 
VALUES ('1','root');

INSERT INTO node (path,name) 
VALUES ('1.2','Node 1');

INSERT INTO node (path,name) 
VALUES ('1.2.3','Node 3');

INSERT INTO node (path,name) 
VALUES ('1.2.3.4','Node 4');

INSERT INTO node (path,name) 
VALUES ('1.2.5','Node 5');
4

2 に答える 2

4

隣接ツリー構造でよく使用される親 ID の代わりに、ltree の実体化されたパスで動作するように、それを見つけて少し変更することができました。

私はまだより良い解決策を望んでいますが、これで仕事が完了すると思います.

ltree パスに加えて、parent_id を追加する必要があるように感じます。これはもちろん、親 ID を参照するほど高速ではないためです。

クレジットはこの男のソリューションに送られます。これは、ltreeのサブパス、ltree2text、およびnlevelを使用してまったく同じことを達成するためにわずかに変更されたコードです。

WITH RECURSIVE c AS (
    SELECT *, 1 as lvl
    FROM node
    WHERE id=1
  UNION ALL
    SELECT node.*, c.lvl + 1 as lvl
    FROM node
    JOIN c ON ltree2text(subpath(node.path,nlevel(node.path)-2 ,nlevel(node.path))) = CONCAT(subpath(c.path,nlevel(c.path)-1,nlevel(c.path)),'.',node.id)
),
maxlvl AS (
  SELECT max(lvl) maxlvl FROM c
),
j AS (
    SELECT c.*, json '[]' children
    FROM c, maxlvl
    WHERE lvl = maxlvl
  UNION ALL
    SELECT (c).*, json_agg(j) children FROM (
      SELECT c, j
      FROM j
      JOIN c ON ltree2text(subpath(j.path,nlevel(j.path)-2,nlevel(j.path))) = CONCAT(subpath(c.path,nlevel(c.path)-1,nlevel(c.path)),'.',j.id)
    ) v
    GROUP BY v.c
)
SELECT row_to_json(j)::text json_tree
FROM j
WHERE lvl = 1;

ただし、これまでのところ、このソリューションには大きな問題があります。エラーについては、以下の画像を参照してください (ノード 5 がありません)。

ノード 5 が JSON オブジェクトにありません

于 2014-11-18T17:06:50.710 に答える