使用Bookshelf进行Postgres物化路径搜索

时间:2014-09-23 17:45:18

标签: sql postgresql bookshelf.js knex.js materialized-path-pattern

让我们说我正在使用物化路径来存储管理链:

  Table: User
  id           name             management_chain
  1            Senior VP        {1}
  2            Middle Manager   {1,2}
  3            Cubicle Slave    {1,2,3}
  4            Janitor          {1,2,4}

如何根据返回所有直接报告的用户ID构建查询,例如,如果给中间经理,则应该返回Cubicle Slave和Janitor,鉴于高级副总裁,它应该返回中间管理器。换句话说,什么是获取management_chain包含在倒数第二个位置查询的id的所有记录的好方法(假设最后一个项代表用户自己的id)

换句话说,我如何表示以下SQL:

SELECT *
FROM USER u 
WHERE u.management_chain @> {stored_variable, u.id}

我现在的JS:

 var collection = Users.forge()
    .query('where', 'management_chain', '@>', [req.user.id, id]);

出了哪些错误

ReferenceError: id is not defined

2 个答案:

答案 0 :(得分:1)

假设management_chain是整数数组(int[]),您可以执行以下操作(在纯SQL中)

select *
from (
  select id,
         name,
         '/'||array_to_string(management_chain, '/') as path
  from users
) t
where path like '%/2/%';

这样可行,因为array_to_string()不会将分隔符附加到字符串的末尾。因此,如果路径包含序列/2/,则意味着有更多节点"低于"那个。 2management_chain的最后一个ID为/2的节点将以/结尾(不会跟踪{{1}}),并且不会包含在结果中。

表达式不会使用索引,因此对于大型表可能不可行。

但是,我不知道这会如何转化为JS的东西。

SQLFiddle示例:http://sqlfiddle.com/#!15/75948/2

答案 1 :(得分:0)

使用RECURSIVE查找

举个例子来看看这段代码:

CREATE VIEW
    mvw_pre_import_cellpath_check
    (
        pkid_cell,
        id_cell  ,
        id_parent,
        has_child,
        id_path  ,
        name_path,
        string_path
    ) AS WITH RECURSIVE cell_paths
    (
        pkid_cell,
        id_cell  ,
        id_parent,
        id_path  ,
        name_path
    ) AS
    (
     SELECT
                tbl_cell.pkid                     ,
                tbl_cell.cell_id                  ,
                tbl_cell.cell_parent_id           ,
                ARRAY[tbl_cell.cell_id]   AS "array",
                ARRAY[tbl_cell.cell_name] AS "array"
           FROM
                ufo.tbl_cell
          WHERE
                (((
                            tbl_cell.cell_parent_id IS NULL)
                        AND (
                            tbl_cell.reject_reason IS NULL))
                    AND (
                        tbl_cell.processed_dt IS NULL))
  UNION ALL
     SELECT
                tbl_cell.pkid                             ,
                tbl_cell.cell_id                          ,
                tbl_cell.cell_parent_id                   ,
                (cell_paths_1.id_path || tbl_cell.cell_id),
                (cell_paths_1.name_path || tbl_cell.cell_name)
           FROM
                (cell_paths cell_paths_1
           JOIN
                ufo.tbl_cell
             ON
                ((
                        tbl_cell.cell_parent_id = cell_paths_1.id_cell)))
          WHERE
                (((
                            NOT (
                                tbl_cell.cell_id = ANY (cell_paths_1.id_path)))
                        AND (
                            tbl_cell.reject_reason IS NULL))
                    AND (
                        tbl_cell.processed_dt IS NULL))
    )
 SELECT
        cell_paths.pkid_cell,
        cell_paths.id_cell  ,
        cell_paths.id_parent,
        (
         SELECT
                    COUNT(*) AS COUNT
               FROM
                    ufo.tbl_cell x
              WHERE
                    ((
                            cell_paths.id_cell = x.cell_id)
                        AND (
                            EXISTS
                            (
                             SELECT
                                        1
                                   FROM
                                        ufo.tbl_cell y
                                  WHERE
                                        (
                                            x.cell_id = y.cell_parent_id))))) AS has_child,
        cell_paths.id_path                                                                ,
        cell_paths.name_path                                                              ,
        array_to_string(cell_paths.name_path, ' -> '::text) AS string_path
   FROM
        cell_paths
   ORDER BY
        cell_paths.id_path;

在寻找递归CTE时,有更多的例子可以在SO上找到。 但与您的示例相反,顶级单元格(管理器)在我的示例中具有parent_id = NULL。这些是不同分支的起点。

HTH