javascript - 如何将我的 ltree 点表示法层次结构改进为嵌套 JSON 脚本?

标签 javascript node.js reduce hierarchical-data ltree

我从数据库收到一组行,其中 parentPath 列格式为 ltree 字符串(点表示法),表示层次结构。我想从我的 Nodejs 服务器返回具有嵌套类别的相同数据。

我拥有的数据:

const categories = [
  {
    id: 1,
    name: "ALL",
    parentPath: "categories",
    translationFr: "Toutes les catégories"
  },
  {
    id: 2,
    name: "LEISURE",
    parentPath: "categories.leisure",
    translationFr: "Loisirs"
  },
  {
    id: 35,
    name: "AUTO",
    parentPath: "categories.services.auto",
    translationFr: "Auto-écoles"
  },
  {
    id: 3,
    name: "MUSEUMS",
    parentPath: "categories.leisure.museums",
    translationFr: "Musées"
  },
  {
    id: 4,
    name: "MONUMENTS",
    parentPath: "categories.leisure.monuments",
    translationFr: "Monuments et patrimoine"
  },
  {
    id: 5,
    name: "OPERAS",
    parentPath: "categories.leisure.operas",
    translationFr: "Opéras"
  },
  {
    id: 6,
    name: "THEATER",
    parentPath: "categories.leisure.theater",
    translationFr: "Théâtres"
  },
  {
    id: 7,
    name: "CINEMAS",
    parentPath: "categories.leisure.cinemas",
    translationFr: "Cinémas"
  },
  {
    id: 8,
    name: "CONCERT",
    parentPath: "categories.leisure.concert",
    translationFr: "Salles de concert"
  },
  {
    id: 9,
    name: "FITNESS",
    parentPath: "categories.leisure.fitness",
    translationFr: "Salles de fitness"
  },
  {
    id: 10,
    name: "CLUBS",
    parentPath: "categories.leisure.clubs",
    translationFr: "Clubs de sport"
  },
  {
    id: 11,
    name: "SENSATIONAL",
    parentPath: "categories.leisure.sensational",
    translationFr: "Sensationnel"
  },
  {
    id: 12,
    name: "HEALTH",
    parentPath: "categories.health",
    translationFr: "Bien-être et beauté"
  },
  {
    id: 13,
    name: "HAIR",
    parentPath: "categories.health.hair",
    translationFr: "Salons de coiffure"
  },
  {
    id: 14,
    name: "CARE",
    parentPath: "categories.health.care",
    translationFr: "Soins"
  },
  {
    id: 15,
    name: "SPAS",
    parentPath: "categories.health.spas",
    translationFr: "Spas"
  },
  {
    id: 16,
    name: "MASSAGE",
    parentPath: "categories.health.massage",
    translationFr: "Massage"
  },
  {
    id: 17,
    name: "FOOD",
    parentPath: "categories.food",
    translationFr: "Restaurants et Bars"
  },
  {
    id: 18,
    name: "NIGHTCLUB",
    parentPath: "categories.food.nightclub",
    translationFr: "Boîtes de nuit"
  },
  {
    id: 19,
    name: "RESTAURANTS",
    parentPath: "categories.food.restaurants",
    translationFr: "Restaurants"
  },
  {
    id: 20,
    name: "BARS",
    parentPath: "categories.food.bars",
    translationFr: "Bars"
  },
  {
    id: 21,
    name: "FASTFOOD",
    parentPath: "categories.food.fastfood",
    translationFr: "Sur le pouce"
  }
]

我想要什么:

[
  {
    name: "LEISURE",
    translationFr: "Loisirs",
    children: [
      { name: "MUSEUMS", translationFr: "Musées" },
      ...
    ]
  },
  {
    name: "HEALTH",
    translationFr: "Santé et bien-être",
    children: [...]
  },
  ...
]

我通过以下代码成功获得了我想要的东西:

const result = categories
  .filter(c => c.name != "ALL") // remove the root of the tree from array
  .reduce((r, s) => {
    // Select everything before the last "." AKA parent category
    const parentCategory = s.parentPath.substring(
      0,
      s.parentPath.lastIndexOf(".")
    );
    let object = r.find(o => o.parentPath === parentCategory);
    if (!object) {
      r.push({ ...s, children: [] });
    } else {
      object.children.push(s);
    }
    return r;
  }, []);

但是这个脚本有几个弱点:

  • 它不适用于 4 层或更多级别的嵌套
  • 如果按此顺序呈现行(3 级嵌套在 2 级嵌套之前),它将不起作用:
categories.leisure.sensational
categories.leisure
categories.leisure.museums

这里有一个天才知道我们如何继续吗?

最佳答案

你可以像这样积累它们:

项目的深度或顺序并不重要,但如果缺少部分路径(如categories.services),则子树将不会包含在输出中.

var children = function (key) {
  return this[key] || (this[key] = [])
}.bind({});

categories.forEach((item) => {
  children(item.parentPath.replace(/(^|\.)\w+$/g, "")).push({
    ...item,
    children: children(item.parentPath)
  });
});

console.log(children(""));

或内联(因为你不能重用children()函数):

var root = categories.reduce((children, item) => {
  children(item.parentPath.replace(/(^|\.)\w+$/g, "")).push({
    ...item,
    children: children(item.parentPath)
  });

  return children;
}, function (key) {
  return this[key] || (this[key] = [])
}.bind({}))("");

console.log(root);

const categories = [
  {
    id: 1,
    name: "ALL",
    parentPath: "categories",
    translationFr: "Toutes les catégories"
  },
  {
    id: 2,
    name: "LEISURE",
    parentPath: "categories.leisure",
    translationFr: "Loisirs"
  },
  {
    id: 35,
    name: "AUTO",
    parentPath: "categories.services.auto",
    translationFr: "Auto-écoles"
  },
  {
    id: 3,
    name: "MUSEUMS",
    parentPath: "categories.leisure.museums",
    translationFr: "Musées"
  },
  {
    id: 4,
    name: "MONUMENTS",
    parentPath: "categories.leisure.monuments",
    translationFr: "Monuments et patrimoine"
  },
  {
    id: 5,
    name: "OPERAS",
    parentPath: "categories.leisure.operas",
    translationFr: "Opéras"
  },
  {
    id: 6,
    name: "THEATER",
    parentPath: "categories.leisure.theater",
    translationFr: "Théâtres"
  },
  {
    id: 7,
    name: "CINEMAS",
    parentPath: "categories.leisure.cinemas",
    translationFr: "Cinémas"
  },
  {
    id: 8,
    name: "CONCERT",
    parentPath: "categories.leisure.concert",
    translationFr: "Salles de concert"
  },
  {
    id: 9,
    name: "FITNESS",
    parentPath: "categories.leisure.fitness",
    translationFr: "Salles de fitness"
  },
  {
    id: 10,
    name: "CLUBS",
    parentPath: "categories.leisure.clubs",
    translationFr: "Clubs de sport"
  },
  {
    id: 11,
    name: "SENSATIONAL",
    parentPath: "categories.leisure.sensational",
    translationFr: "Sensationnel"
  },
  {
    id: 12,
    name: "HEALTH",
    parentPath: "categories.health",
    translationFr: "Bien-être et beauté"
  },
  {
    id: 13,
    name: "HAIR",
    parentPath: "categories.health.hair",
    translationFr: "Salons de coiffure"
  },
  {
    id: 14,
    name: "CARE",
    parentPath: "categories.health.care",
    translationFr: "Soins"
  },
  {
    id: 15,
    name: "SPAS",
    parentPath: "categories.health.spas",
    translationFr: "Spas"
  },
  {
    id: 16,
    name: "MASSAGE",
    parentPath: "categories.health.massage",
    translationFr: "Massage"
  },
  {
    id: 17,
    name: "FOOD",
    parentPath: "categories.food",
    translationFr: "Restaurants et Bars"
  },
  {
    id: 18,
    name: "NIGHTCLUB",
    parentPath: "categories.food.nightclub",
    translationFr: "Boîtes de nuit"
  },
  {
    id: 19,
    name: "RESTAURANTS",
    parentPath: "categories.food.restaurants",
    translationFr: "Restaurants"
  },
  {
    id: 20,
    name: "BARS",
    parentPath: "categories.food.bars",
    translationFr: "Bars"
  },
  {
    id: 21,
    name: "FASTFOOD",
    parentPath: "categories.food.fastfood",
    translationFr: "Sur le pouce"
  }
];

var root = categories.reduce((children, item) => {
  children(item.parentPath.replace(/(^|\.)\w+$/g, "")).push({
    ...item,
    children: children(item.parentPath)
  });
  
  return children;
}, function(key){ 
  return this[key] || (this[key]=[]) 
}.bind({}) )("");

console.log(root);

关于javascript - 如何将我的 ltree 点表示法层次结构改进为嵌套 JSON 脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58434920/

相关文章:

javascript - 为什么 moment-timezone 在 webpack 4 和/或 create react app 4 中使用的空间要少得多?

node.js - Express路由器调用错误的路由

node.js - 如何将 Sails.js 应用程序安装为快速中间件

node.js - 如何对 HTML 元素属性进行编码

javascript - 在javascript中使用reduce或filter计算对象的数量

arrays - 包含自定义类的数组总和(Swift)

javascript - 重试加载 iframe 直至成功?

javascript - jQuery:将文本区域滚动到给定位置

javascript - Bootstrap 的 javascript 在本地工作,但在部署到服务器时不工作

javascript - 如何使用reduce 测试数组的Math.max 函数