映射JSON数据反向?

时间:2017-02-03 08:03:20

标签: javascript arrays json mapping

我被困在一个可能很简单的任务上,但找不到任何解决方案。 我有一些JSON数据 - 让我们说:

[{
  "_id": 1,
  "type": "person",
  "Name": "Hans",
  "WorksFor": ["3", "4"]
}, {
  "_id": 2,
  "type": "person",
  "Name": "Michael",
  "WorksFor": ["3"]
}, {
  "_id": 3,
  "type": "department",
  "Name": "Marketing"
}, {
  "_id": 4,
  "type": "department",
  "Name": "Sales"
}]

当我了解here时,使用部门的地图数组让他们共同工作的所有人员和部门变得非常简单。 然后我可以将相应的部门映射到Person并接收类似的内容:

[{
  "_id": 1,
  "type": "person",
  "Name": "Hans",
  "WorksFor": ["3", "4"],
  "Readable": ["Marketing", "Sales"]
}, {
  "_id": 2,
  "type": "person",
  "Name": "Michael",
  "WorksFor": ["3"],
  "Readable": ["Sales"]
}]

但对于另一个界面,我需要“反过来”的数据,例如。

[{
  "_id": 3,
  "type": "department",
  "Name": "Marketing",
  "employees": [
        "Hans", "Michael"
    ]
}, {
  "_id": 4,
  "type": "department",
  "Name": "Sales",
  "employees": [
        "Hans"
    ]
  }]

有没有合适的方法来实现这种结构?两天的尝试没有把我带到任何地方......

6 个答案:

答案 0 :(得分:1)

您可以尝试这样的事情:



var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}]
var ignoreDept = ['person'];

var result = data.reduce(function(p,c,i,a){
  if(ignoreDept.indexOf(c.type) < 0){
    c.employees = a.reduce(function(arr,emp){
      if(emp.WorksFor && emp.WorksFor.indexOf(c._id.toString()) > -1){
        arr.push(emp.Name)
      }
      return arr;
    },[]);
    p.push(c);
  }
  return p;
}, []);

console.log(result)
&#13;
&#13;
&#13;

答案 1 :(得分:1)

使用Array.prototype.filter()Array.prototype.forEach()函数的解决方案:

&#13;
&#13;
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}],
    // getting separated "lists" of departments and employees(persons) 
    deps = data.filter(function(o){ return o.type === "department"; }),
    persons = data.filter(function(o){ return o.type === "person"; });
    
deps.forEach(function (d) {
  d['employees'] = d['employees'] || [];
  persons.forEach(function (p) {
      if (p.WorksFor.indexOf(String(d._id)) !== -1) {  // check the `id` coincidence between the employee and the department
        d['employees'].push(p.Name);
      }
  });
});
    
console.log(deps);
&#13;
&#13;
&#13;

答案 2 :(得分:1)

您可以为每个数组使用哈希表和单个循环。

方法:

  • Array#reduce用于迭代数组并返回结果,
  • Array#forEach用于循环内部数组WorksFor
  • Object.create(null)生成没有任何原型的对象,
  • 其他一些模式,例如hash
  • 之上的闭包
  • 使用logical OR ||检查虚假值并将对象作为默认值。

    hash[b] = hash[b] || { _id: b, employees: [] };
    

var data = [{ _id: 1, type: "person", Name: "Hans", WorksFor: [3, 4] }, { _id: 2, type: "person", Name: "Michael", WorksFor: [3] }, { _id: 3, type: "department", Name: "Marketing" }, { _id: 4, type: "department", Name: "Sales" }],
    result = data.reduce(function (hash) {
        return function (r, a) {
            if (a.type === 'person') {
                a.WorksFor.forEach(function (b) {
                    hash[b] = hash[b] || { _id: b, employees: [] };
                    hash[b].employees.push(a.Name);
                });
            }
            if (a.type === 'department') {
                hash[a._id] = hash[a._id] || { _id: b, employees: [] };
                hash[a._id].type = a.type;
                hash[a._id].Name = a.Name;
                r.push(hash[a._id]);
            }
            return r;
        };
    }(Object.create(null)), []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 3 :(得分:1)

var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"] }, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"] }, { "_id": 3, "type": "department", "Name": "Marketing" }, { "_id": 4, "type": "department", "Name": "Sales" }];

var departments = [],
    persons = [];

data.forEach(e => {
  if (e.type === "person") {
    persons.push(e);
  } else if (e.type === "department") {
    departments.push(e);
    e.employees = [];
  }
});

departments.forEach(d => {
  var workers = persons.filter(p => p.WorksFor.indexOf(d._id.toString()) > -1)
                     /*.map(p => p.Name)*/    // add this if you only need the name instead of the complete "person"

  d.employees = d.employees.concat(workers);
});

console.log(JSON.stringify(departments, null, 4));

答案 4 :(得分:0)

这是一种可以获得第一个映射的方法。我已经添加了一些评论,以便您可以跟进,并希望您能找到第二个问题的答案。

// First, let's get just the items in this array that identify persons
// I've called this array "data"
data.filter(x => x.type === 'person') 
    // Now let's map over them
    .map(person =>
      // We want all of the data associated with this person, so let's
      // use Object.assign to duplicate that data for us
      Object.assign({}, person, {
          // In addition, we want to map the ID of the WorksFor array to the Name
          // of the corresponding department. Assuming that the _id key is unique,
          // we can due this simply by mapping over the WorksFor array and finding
          // those values within the original array.
          Readable: person.WorksFor.map(wfId =>
             // Notice here the parseInt. This will not work without it due to
             // the type difference between WorksFor (string) and _id (integer)
             data.find(d => d._id === parseInt(wfId)).Name
          )
      })
);

答案 5 :(得分:0)

var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}];

var dep = {};

data.forEach(e => (e.type === 'person' && e.WorksFor.forEach(d => dep[d]? dep[d].push(e.Name): dep[d] = [e.Name])));

data.forEach(e => (e.type == 'department' && (e.employees = dep[e._id] || [])));

data = data.filter(e => e.type == 'department');

console.log(data);