javascript - 有选择地展平嵌套 JSON 结构

标签 javascript python json elasticsearch clojure

所以这是一个我不知道从哪里开始的问题,所以即使只是一个指向正确方向的指针也会很棒。

所以我的数据看起来像这样:

data = {
   "agg": {
      "agg1": [
         {
            "keyWeWant": "*-20.0",
            "asdf": 0,
            "asdf": 20,
            "asdf": 14,
            "some_nested_agg": [
               {
                  "keyWeWant2": 20,
                  "to": 25,
                  "doc_count": 4,
                  "some_nested_agg2": {
                     "count": 7,
                     "min": 2,
                     "max": 5,
                     "keyWeWant3": 2.857142857142857,
                     "sum": 20
                  }
               },
               {
                  "keyWeWant2": 25,
                  "to": 30,
                  "doc_count": 10,
                  "some_nested_agg2": {
                     "count": 16,
                     "min": 2,
                     "max": 10,
                     "keyWeWant3": 6.375,
                     "sum": 102
                  }
               }
            ]
         },
         {
         ...
         },
         {
         ...
         },
         ...
      ]
   }
}

现在,从示例中,“agg”内有 N 个“agg1”结果,每个“agg1”结果内有一个“keyWeWant”。每个“agg1”结果还有一个“some_nested_agg”结果列表,每个结果都包含一个“keyWeWant2”。每个“keyWeWant2”值都与层次结构中某个位置的单个“keyWeWant”值相关联。类似地,每个“keyWeWant2”也包含“some_nested_agg2”的一组结果(这次不是列表,而是 map )。每组结果都包含一个“keyWeWant3”。

现在我想扁平化这个结构,同时仍然保留“keyWeWant”、“keyWeWant2”和“keyWeWant3”之间的关联(我本质上是去规范化)以获得类似这样的结果:

我希望函数看起来像什么:

[
   {
      "keyWeWant" : "*-20",
      "keyWeWant2" : 20,
      "keyWeWant3" : 2.857142857142857
   },
   {
      "keyWeWant" : "*-20",
      "keyWeWant2" : 25,
      "keyWeWant3" : 6.375
   },
   {
   ...
   },
   {
   ...
   }
]

这是一个只有深度 3 的示例,但可以有任意深度,其中一些嵌套值是列表,一些是数组/列表。

我想做的是编写一个函数来获取我想要的键以及在哪里可以找到它们,然后获取键并进行非规范化。

看起来像这样的东西:

function_name(data_map, {
   "keyWeWant" : ['agg', 'agg1'],
   "keyWeWant2" : ['agg', 'agg1', 'some_nested_agg'],
   "keyWeWant" : ['agg', 'agg1', 'some_nested_agg', 'some_nested_agg2']
})

有什么想法吗?我熟悉 Java、Clojure、JavaScript 和 Python,只是在寻找一种相对简单的方法来解决这个问题。

最佳答案

以下是您可以使用的 JavaScript (ES6) 函数:

function flatten(data, keys) {
    var key = keys[0];
    if (key in data)
        keys = keys.slice(1);
    var res = keys.length && Object.keys(data)
        .map( key => data[key] )
        .filter( val => Object(val) === val )
        .reduce( (res, val) => res.concat(flatten(val, keys)), []);
    return !(key in data) ? res
        : (res || [{}]).map ( obj => Object.assign(obj, { [key]: data[key] }) );
}

// Sample data
var data = {
   "agg": {
      "agg1": [
         {
            "keyWeWant": "*-20.0",
            "asdf": 0,
            "asdf": 20,
            "asdf": 14,
            "some_nested_agg": [
               {
                  "keyWeWant2": 20,
                  "to": 25,
                  "doc_count": 4,
                  "some_nested_agg2": {
                     "count": 7,
                     "min": 2,
                     "max": 5,
                     "keyWeWant3": 2.857142857142857,
                     "sum": 20
                  }
               },
               {
                  "keyWeWant2": 25,
                  "to": 30,
                  "doc_count": 10,
                  "some_nested_agg2": {
                     "count": 16,
                     "min": 2,
                     "max": 10,
                     "keyWeWant3": 6.375,
                     "sum": 102
                  }
               }
            ]
         },
      ]
   }
};

// Flatten it by array of keys
var res = flatten(data, ['keyWeWant', 'keyWeWant2', 'keyWeWant3']);

// Output result
console.log(res);

使用路径的替代方法

正如注释中所指出的,上面的代码没有使用路径信息;它只是在所有数组中查找。如果正在查找的键也出现在应忽略的路径中,这可能会成为一个问题。

以下替代方案将使用路径信息,该信息应作为子数组的数组传递,其中每个子数组首先列出路径键,并将要保留的值键作为最后一个元素:

function flatten(data, [path, ...paths]) {
    return path && (
        Array.isArray(data)
            ? data.reduce( (res, item) => res.concat(flatten(item, arguments[1])), [] )
            : path[0] in data && (
                path.length > 1 
                    ? flatten(data[path[0]], [path.slice(1), ...paths])
                    : (flatten(data, paths) || [{}]).map ( 
                        item => Object.assign(item, { [path[0]]: data[path[0]] }) 
                    )
            )
    );
}

// Sample data
var data = {
   "agg": {
      "agg1": [
         {
            "keyWeWant": "*-20.0",
            "asdf": 0,
            "asdf": 20,
            "asdf": 14,
            "some_nested_agg": [
               {
                  "keyWeWant2": 20,
                  "to": 25,
                  "doc_count": 4,
                  "some_nested_agg2": {
                     "count": 7,
                     "min": 2,
                     "max": 5,
                     "keyWeWant3": 2.857142857142857,
                     "sum": 20
                  }
               },
               {
                  "keyWeWant2": 25,
                  "to": 30,
                  "doc_count": 10,
                  "some_nested_agg2": {
                     "count": 16,
                     "min": 2,
                     "max": 10,
                     "keyWeWant3": 6.375,
                     "sum": 102
                  }
               }
            ]
         },
      ]
   }
};

// Flatten it by array of keys
var res = flatten(data, [
    ['agg', 'agg1', 'keyWeWant'], 
    ['some_nested_agg', 'keyWeWant2'], 
    ['some_nested_agg2', 'keyWeWant3']]);

// Output result
console.log(res);

关于javascript - 有选择地展平嵌套 JSON 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39672892/

相关文章:

javascript - jquery 和 json 数组

javascript - 在 AngularJS 中上传文件

python - flask jsonify : object is not iterable

python - Anaconda-navigator : byte indices must be integers or slices, 不是 str

iOS - 将 JSON 对象转换为有序数组

javascript - 使用 Javascript 进行(多次)重定向后获取最终 URL

javascript - socket.io 服务器对象选项,两者之间有什么影响?

python - 如何使数据框全局化并在函数中使用它?

java - Java 中的 JSON 数组

java - 没有附加适配器,在 fragment 中使用 reyclerview 和 json 跳过布局