0

我正在尝试创建一个函数,该函数可以将对象的嵌套集合模型数组转换为对象数组中的普通对象嵌套数组。

目前,我对深度限制为 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

嵌套集模型是一种处理分层数据的方法,它将子节点包含在边界中(通常称为lftand rgt)。因此,如果 的lftrgt的值node1介于 的lftrgt的值之间node2,则意味着它node1node2(我希望澄清了)的孩子。

例如,我有以下数组:

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
  }
]

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

{
  id: 1,
  name: "Products",
  subcategories: [
    {
      id: 2,
      name: "Boats",
      subcategories: [
        {
          id: 3,
          name: "Rescue Boats"
        },
        {
          id: 4,
          name: "Dive Boats"
        },
        {
          id: 5,
          name: "Tamarans"
        },
        {
          id: 6,
          name: "Dragon Boats"
        },
        {
          id: 7,
          name: "Kayaks"
        },
        {
          id: 8,
          name: "Speedboats"
        }
      ]
    },
    {
      id: 9,
      name: "Other Products",
      subcategories: [
        {
          id: 10,
          name: "Slides"
        },
        {
          id: 11,
          name: "Buoys",
        }
      ]
    }
  ]
}
4

1 回答 1

1

我写了这个递归解决方案。希望它可以提供帮助。如果您有任何疑问,请问我。我只是检查一个元素是否在另一个元素的左右属性内。在这种情况下,我将它添加到他的父亲(和每个anchestor)中。我重复相同的操作,直到不再有“父亲”。

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));

于 2019-05-13T15:59:46.737 回答