从对象数组中动态创建嵌套json

create nested json from array of objects dynamically

本文关键字:创建 嵌套 json 动态 对象 数组      更新时间:2023-09-26

我有一个类似的对象数组

{ title: "A", parent_id: "root",has_children: true}
{ title: "A1", parent_id: "A",has_children: true}
{ title: "A11", parent_id: "A1",has_children: false}
{ title: "A12", parent_id: "A1",has_children: false}
{ title: "A13", parent_id: "A1",has_children: false}
{ title: "B", parent_id: "root",has_children: true}
{ title: "B1", parent_id: "A",has_children: true}
{ title: "B11", parent_id: "B1",has_children: false}
{ title: "B12", parent_id: "B1",has_children: false}
{ title: "B13", parent_id: "B1",has_children: false}

每条记录都有params,说明它是否有子卡以及该卡的父卡是什么。

带"root"的记录是顶级卡。

根据上面的数据,我想要一些类似于下面的东西

[
  {
    "title": "A",
    "children": [
      {
        "title": "A1",
        "children": [
          {
            "title": "A11"
          },
          {
            "title": "A12"
          },
          {
            "title": "A13."
          }
        ]
      },
      {
        "title": "A2",
        "children": [
          {
            "title": "A21"
          },
          {
            "title": "A22"
          },
          {
            "title": "A23"
          }
        ]
      }
    ]
  },
  {
    "title": "B",
    "children": [
      {
        "title": "B1",
        "children": [
          {
            "title": "B11"
          },
          {
            "title": "B12"
          },
          {
            "title": "B13."
          }
        ]
      },
      {
        "title": "B2",
        "children": [
          {
            "title": "B21"
          },
          {
            "title": "B22"
          },
          {
            "title": "B23"
          }
        ]
      }
    ]
  }
]

我试了一段时间,但做不到,以下是我尝试的内容

我正在流星中使用mongodb 进行此操作

getUserJSON  = function(userId){
  var userJSON = [];
  getJSONCards(userId,'root', userJSON)
}
getJSONCards = function(userId, parent_id, userData){
  var allCards = userCards.find({ $and: [ { user_id: userId }, { parent_id: parent_id } ] }).fetch();
  if(allCards.length > 0){
    allCards.forEach(function (cardInfo) {
      var isExist = $.grep(userData, function(e){ return e.content === parent_id; });
      if(isExist){
        //here I don't know how to insert nested cards
      }
    });
  }
}

但我希望使用简单的js解决方案

下面的解决方案使用以下方法:

  1. 使用Array.prototype.reduce(),根据allCards集合中的title值将每个项索引到对象中
  2. 使用Array.prototype.filter()将root项保留在集合中,同时将每个项作为子项分配给它们各自的父项(如果它们确实存在于indexed变量中)

var allCards = [
  { title: "A", parent_id: "root", has_children: true},
  { title: "A1", parent_id: "A", has_children: true},
  { title: "A11", parent_id: "A1", has_children: false},
  { title: "A12", parent_id: "A1", has_children: false},
  { title: "A13", parent_id: "A1", has_children: false},
  { title: "B", parent_id: "root", has_children: true},
  { title: "B1", parent_id: "A", has_children: true},
  { title: "B11", parent_id: "B1", has_children: false},
  { title: "B12", parent_id: "B1", has_children: false},
  { title: "B13", parent_id: "B1", has_children: false}
];
// index each item by title
var indexed = allCards.reduce(function(result, item) {
  result[item.title] = item;
  return result;
}, {});
// retain the root items only
var result = allCards.filter(function(item) {
  
  // get parent
  var parent = indexed[item.parent_id];
  
  // make sure to remove unnecessary keys
  delete item.parent_id;
  delete item.has_children;
  
  // has parent?
  if(parent) {
    // add item as a child
    parent.children = (parent.children || []).concat(item);
  }
  
  // This part determines if the item is a root item or not
  return !parent;
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

这里有一种方法。迭代对象数组,为每个对象构建一个新对象,并将其存储在缓存中,以便在处理其子对象时直接修改该对象。父母必须出现在孩子面前才能起作用,否则你必须多次通过。

// define data array
var data = [
    { title: "A", parent_id: "root",has_children: true},
    { title: "A1", parent_id: "A",has_children: true},
    { title: "A11", parent_id: "A1",has_children: false},
    { title: "A12", parent_id: "A1",has_children: false},
    { title: "A13", parent_id: "A1",has_children: false},
    { title: "B", parent_id: "root",has_children: true},
    { title: "B1", parent_id: "A",has_children: true},
    { title: "B11", parent_id: "B1",has_children: false},
    { title: "B12", parent_id: "B1",has_children: false},
    { title: "B13", parent_id: "B1",has_children: false}
];
var root = {};
var parentCache = {};
// for each element definition in the data array
for (var i = 0; i < data.length; i++) {
    var element = data[i];
    var title = element.title;
    // XXX - check for duplicate title here.
    // create a new object and initialize
    var newObj = {"title" : title};
    if (element.has_children) {
        newObj["children"] = [];
    }
    // put this object into its parent
    if (element.parent_id === "root") {
        root[title] = newObj;
    } else {
        // XXX - if the parent isn't defined first this will fail
        var parent = parentCache[element.parent_id];
        parent.children.push(newObj);
    }
    // store this object in case it is a parent
    parentCache[title] = newObj;
}
console.log(JSON.stringify(root));