繁体   English   中英

通过node.js中的多个字段对JSON进行分组

[英]Grouping JSON by multiple fields in node.js

我有一个JSON如下。

 var test = [{ "id": "3", "city": "seattle", "place" : "xxx", "usage" : "163612", "available": "162500" }, { "id": "4", "city": "washington", "place" : "xxx", "usage" : "52542", "available": "86624" }, { "id": "3", "city": "seattle", "place" : "yyy", "usage" : "163612", "available": "962500" }, { "id": "5", "city": "seattle", "place" : "yyy", "usage" : "562", "available": "24252" }, { "id": "4", "city": "washington", "place" : "yyy", "usage" : "163612", "available": "319250" }] 

我想通过'id'和'city'将这个JSON分组。 新形成的分组JSON应如下所示。

 [ { "3": { "seattle": [ { "xxx": { "usage": "163612", "available": "162500" } }, { "yyy": { "usage": "163612", "available": "962500" } } ] } }, { "4": { "washington": [ { "xxx": { "usage": "52542", "available": "86624" } }, { "yyy": { "usage": "163612", "available": "319250" } } ] } }, { "5": { "seattle": [ { "xxx": { "usage": "562", "available": "24252" } } ] } } ] 

我试着循环和排序,我无法得到所需的结果。 有没有办法构建这个JSON。

以下是通过多个字段进行分组的一种方法:

http://jsbin.com/xixemo/edit?js,console

(function () {
  "use strict";

  var test = [{

   "id": "3",
   "city": "seattle",
   "place" : "xxx",
   "usage" : "163612",
   "available": "162500"

}, {

   "id": "4",
   "city": "washington",
   "place" : "xxx",
   "usage" : "52542",
   "available": "86624"

}, {

   "id": "3",
   "city": "seattle",
   "place" : "yyy",
   "usage" : "163612",
   "available": "962500"

},
{

   "id": "5",
   "city": "seattle",
   "place" : "yyy",
   "usage" : "562",
   "available": "24252"
},
{

   "id": "4",
   "city": "washington",
   "place" : "yyy",
   "usage" : "163612",
   "available": "319250"

}],
      getRemainingProperties = function (obj, propertiesToExclude) {
        return Object.keys(obj)
          .filter(function (key) {
            return !propertiesToExclude.includes(key);
          })  
          .reduce(function (acc, curr) {
            var result = {};

            if (!acc) {
              result[curr] = obj[curr];
              return result;
            }
            result = acc;
            result[curr] = obj[curr];
            return result;          
          }, undefined);
      },
      excludedProperties = ["id", "city", "place"],
      transformCity = function (cityInformation) {
        var id = {},        
            city = {},
            place = {},
            remainder = getRemainingProperties(cityInformation, excludedProperties);
        place[cityInformation.place] = remainder;
        city[cityInformation.city] = [place];
        id[cityInformation.id] = city;
        return id;
      },
      initialReduceUndefinedValue,
      idExists = function (searchArray, id) {
        return searchArray.reduce(function (acc, curr) {
          if (!acc){
            return curr.hasOwnProperty(id);
          }
          return true;
        }, undefined);
      },
      lift = function (array) {
        //returns an object from inside container array without using array index
        if (!Array.isArray(array)) {
          return array;
        }
        return array.reduce(function (acc, curr) {
          return curr;
        });
      },
      answer = test.reduce(function (acc, curr) {
        var result, 
            matchingId, //create a new object that will have appended properties for the current city
            missingPlace = {};

        if (!acc) {
          return [transformCity(curr)];
        }
        if (idExists(acc, curr.id)) {
          result = acc.filter(function (obj) {
            //store the unmodified objects to return
            return !obj.hasOwnProperty(curr.id);
          });
          matchingId = lift(acc.filter(function (obj) {
            return obj.hasOwnProperty(curr.id);
          }));

          if (!matchingId[curr.id].hasOwnProperty(curr.city)) {
            //if the object does not have the city, then add the city
            matchingId[curr.city] = {};
          }
          if (!matchingId[curr.id][curr.city].hasOwnProperty(curr.place)) {
            //if the object does not have the place, then add the place            
            missingPlace[curr.place] = getRemainingProperties(curr, excludedProperties);
            matchingId[curr.id][curr.city].push(missingPlace);
          }
          result.push(matchingId);//add here just incase a city is duplicated
          return result;
        } else {//unique city id found, add new city
          acc.push(transformCity(curr));
        }
        return acc;
      }, initialReduceUndefinedValue);

  console.log(answer);
}());

我已经概括了其余属性的包含,因此不必明确定义它们(根据评论中的OP的要求)。

我试图避免使用for循环,以便从解决方案中提取迭代细节。 我还采用了函数式编程方法,并试图避免创建带副作用的函数。 在加载到jsbin的解决方案中,我添加了一个用于数组包含的polyfill,它有望进入ECMAScript版本7(预计在2016年)。 有一个有用的“Javascript中的函数编程”教程可能会有所帮助:

http://jhusain.github.io/learnrx/

此答案的可能扩展是对分组数据进行排序以匹配OP列出的示例输出。

我不知道那是不是你要找的东西。

  var newObj = []; for (var i in test) { var cityObj = test[i]; var newItem = {}; var foundItem = false; for (var j in newObj) { var existingItem = newObj[j]; if (newObj[j].hasOwnProperty(cityObj.id)) { foundItem = j; } } if (!foundItem) { newItem[cityObj.id] = {}; newItem[cityObj.id][cityObj.city] = {}; newItem[cityObj.id][cityObj.city][cityObj.place] = { usage: cityObj.usage, available: cityObj.available }; newObj.push(newItem); } else { newObj[foundItem][cityObj.id][cityObj.city][cityObj.place] = { usage: cityObj.usage, available: cityObj.available }; } } console.dir(newObj); 

如果有帮助,请告诉我。

已更改以符合您的说明:

  var newObj = []; for (var i in test) { var cityObj = test[i]; var newItem = {}; var foundItem = false; for (var j in newObj) { var existingItem = newObj[j]; if (newObj[j].hasOwnProperty(cityObj.id)) { foundItem = j; } } if (!foundItem) { newItem[cityObj.id] = {}; newItem[cityObj.id][cityObj.city] = []; var place = {}; place[cityObj.place] = { usage: cityObj.usage, available: cityObj.available }; newItem[cityObj.id][cityObj.city].push(place); newObj.push(newItem); } else { var place = {}; place[cityObj.place] = { usage: cityObj.usage, available: cityObj.available }; newObj[foundItem][cityObj.id][cityObj.city].push(place); } } console.dir(newObj); 

我认为这将是一个更好的解决方案:

function group(data, column) {
  var generatedData = {};
  for (var i in data){
    var dt = data[i];
    var key = dt[column];
    if (!(key in generatedData)) {
      generatedData[key] = [];
    }
    generatedData[key].push(dt);
  }
  return generatedData;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM