如何从嵌套集模型中的对象数组生成对象的嵌套数组?

时间:2019-05-13 14:31:05

标签: javascript

我正在尝试创建一个函数,该函数可以将nested set model对象数组转换为对象数组内的普通嵌套对象数组。

当前,我对深度限制为2的临时解决方案不满意。基本上,它是使用某些Knex的服务器端控制器:

const getCategories = (res, db) => {
  db.raw(`
    SELECT child.id, child.name, child.path
    FROM product_category parent
    JOIN product_category child
    ON child.lower BETWEEN parent.lower AND parent.upper
    WHERE parent.id = 1
      AND
        (
          SELECT COUNT(*)
          FROM product_category node
          WHERE child.lower BETWEEN node.lower AND node.upper
            AND node.lower BETWEEN parent.lower AND parent.upper
        ) = 2 
    ORDER BY child.id
  `)
  .then(categories => {
    if (categories.rows.length) {
      const categoryPromises = categories.rows.map(category => {
        return db.raw(`
          SELECT child.id, child.name, child.path
          FROM product_category parent
          JOIN product_category child
          ON child.lower BETWEEN parent.lower AND parent.upper
          WHERE parent.id = ${category.id}
          AND
            (
              SELECT COUNT(*)
              FROM product_category node
              WHERE child.lower BETWEEN node.lower AND node.upper
                AND node.lower BETWEEN parent.lower AND parent.upper
            ) = 2 
        `)
        .then(subcategories => {
          return { ...category, subcategories: subcategories.rows }
        })
      })

      return Promise.all(categoryPromises)
      .then(products => {
        res.json(products)
      })
    } else {
      res.status(400).json("No categories")
    }
  })
}

模式在这里:http://sqlfiddle.com/#!17/a20af

嵌套集模型是一种处理层次结构数据的方法,该方法将子节点封闭在边界中(通常称为lftrgt)。因此,如果lft的{​​{1}}和rgt值介于node1的{​​{1}}和lft值之间,则表示{{1} }是rgt的子代(我希望这可以解决)。

例如,我有以下数组:

node2

我希望它具有类似这样的输出(如果有多个根节点,则为数组):

node1

1 个答案:

答案 0 :(得分:1)

我写了这个递归解决方案。希望能有所帮助。如果您有任何疑问,请问我。 我只是检查一个元素是否在另一个元素的right和left属性内。在这种情况下,我将其添加到他的父亲(和每个主持人)中。我重复相同的操作,直到没有“父亲”为止。

const categories = [
  {
      id: 1,
      name: "Products",
      lft: 1,
      rgt: 22
  },
  {
      id: 2,
      name: "Boats",
      lft: 2,
      rgt: 15
  },
  {
      id: 3,
      name: "Rescue Boats",
      lft: 3,
      rgt: 4
  },
  {
      id: 4,
      name: "Dive Boats",
      lft: 5,
      rgt: 6
  },
  {
      id: 5,
      name: "Tamarans",
      lft: 7,
      rgt: 8
  },
  {
      id: 6,
      name: "Dragon Boats",
      lft: 9,
      rgt: 10
  },
  {
      id: 7,
      name: "Kayaks",
      lft: 11,
      rgt: 12
  },
  {
      id: 8,
      name: "Speedboats",
      lft: 13,
      rgt: 14
  },
  {
      id: 9,
      name: "Other Products",
      lft: 16,
      rgt: 21
  },
  {
      id: 10,
      name: "Slides",
      lft: 17,
      rgt: 18
  },
  {
      id: 11,
      name: "Buoys",
      lft: 19,
      rgt: 20
  }
]

function create_tree(array){
  if(array.every(x => array.every(y => !(y.lft > x.lft && y.rgt < x.rgt))))
    return array.map(x => {return{id:x.id, name:x.name, subcategories: x.subcategories}});
  else
  return create_tree(array.map(x => {return {
    id: x.id,
    name: x.name,
    lft: x.lft,
    rgt: x.rgt,
    subcategories: array.filter(y => y.lft > x.lft && y.rgt < x.rgt).map(t => {return (t.subcategories) ? {id: t.id, name: t.name, subcategories: t.subcategories} : {id: t.id, name: t.name}})
  }}).filter(t => t.subcategories && t.subcategories.length > 0));
}

console.log(create_tree(categories));