如何在Groovy中展平和拆分此JSON?

如何在Groovy中展平和拆分此JSON?,json,groovy,nested,flatten,Json,Groovy,Nested,Flatten,我需要一些帮助来编写Groovy脚本,以便基于嵌套数组元素将JSON扁平化并拆分为多个JSON-s。以下是原始JSON: { "input_query": { "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1", "user_uid": 5467890, "shopping_list": [ { "article_id": 311729, "current_pric

我需要一些帮助来编写Groovy脚本,以便基于嵌套数组元素将JSON扁平化并拆分为多个JSON-s。以下是原始JSON:

{
  "input_query": {
    "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
    "user_uid": 5467890,
    "shopping_list": [
      {
        "article_id": 311729,
        "current_price_without_promo": 7.69,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 229752,
        "current_price_without_promo": 11.29,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 193672,
        "current_price_without_promo": 79.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 261657,
        "current_price_without_promo": 16.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 318153,
        "current_price_without_promo": 13.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      }
    ],
    "discount_params_per_article": [
      {
        "article_id": 311729,
        "min_discount": 0,
        "max_discount": 4.12,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 229752,
        "min_discount": 0,
        "max_discount": 7.52,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 193672,
        "min_discount": 0,
        "max_discount": 60,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 261657,
        "min_discount": 0,
        "max_discount": 12.4,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 318153,
        "min_discount": 0,
        "max_discount": 8,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      }
    ],
    "target_probability_increase": null,
    "request_time": "2019-12-21T21:32:13.018635"
  },
  "total_discount": 0.94,
  "article_discounts": [
    {
      "article_id": 311729,
      "discount": 0.04
    },
    {
      "article_id": 229752,
      "discount": 0.08
    },
    {
      "article_id": 193672,
      "discount": 0.61
    },
    {
      "article_id": 261657,
      "discount": 0.13
    },
    {
      "article_id": 318153,
      "discount": 0.08
    }
  ]
}
我想做的是将原始JSON展平为JSON-s数组,如下所示:

[{
  "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
  "user_uid": 5467890,
  "article_id": 318153,
  "current_price_without_promo": 13.99,
  "promo_discount": 0,
  "count": 1,
  "apply_discount": true,
  "min_discount": 0,
  "max_discount": 8,
  "imposed_discount": null,
  "article_target_probability_increase": 1.15,
  "discount_downscale_factor": 1,
  "target_probability_increase": null,
  "request_time": "2019-12-21T21:32:13.018635",
  "total_discount": 0.94,
  "discount": 0.08
},
{
  "discount_guid": ...
},
...
]
import groovy.json.*

def str = '''
{
  "input_query": {
    "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
    "user_uid": 5467890,
    "shopping_list": [
      {
        "article_id": 311729,
        "current_price_without_promo": 7.69,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 229752,
        "current_price_without_promo": 11.29,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 193672,
        "current_price_without_promo": 79.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 261657,
        "current_price_without_promo": 16.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 318153,
        "current_price_without_promo": 13.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      }
    ],
    "discount_params_per_article": [
      {
        "article_id": 311729,
        "min_discount": 0,
        "max_discount": 4.12,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 229752,
        "min_discount": 0,
        "max_discount": 7.52,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 193672,
        "min_discount": 0,
        "max_discount": 60,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 261657,
        "min_discount": 0,
        "max_discount": 12.4,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 318153,
        "min_discount": 0,
        "max_discount": 8,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      }
    ],
    "target_probability_increase": null,
    "request_time": "2019-12-21T21:32:13.018635"
  },
  "total_discount": 0.94,
  "article_discounts": [
    {
      "article_id": 311729,
      "discount": 0.04
    },
    {
      "article_id": 229752,
      "discount": 0.08
    },
    {
      "article_id": 193672,
      "discount": 0.61
    },
    {
      "article_id": 261657,
      "discount": 0.13
    },
    {
      "article_id": 318153,
      "discount": 0.08
    }
  ]
}
'''

def json = new JsonSlurper().parseText(str) 

// a predicate to check if a value is a plain value vs map or list
def isPlain     = { v -> !(v instanceof Map) && !(v instanceof List) }

// for the two maps json.input_query and the root level json map, 
// find all plain values
def plainValues = json.input_query.findAll { k, v -> isPlain(v) } +
                  json.findAll { k, v -> isPlain(v) } 

// find the three lists of maps, group by article_id and add the 
// values for each article id to a cumulative map and finally 
// add the plain values collected above to each cumulative map
def result = (json.input_query.shopping_list +
              json.input_query.discount_params_per_article +
              json.article_discounts).groupBy { 
                it.article_id 
              }.values().collect { listOfMaps -> 
                listOfMaps.sum() + plainValues
              }

// print result
result.each { m -> 
  println "-----"
  m.sort().each { k, v -> 
    println "${k.padLeft(35)} -> $v"
  }
}
我通过这种方式获得了一个扁平JSON:

import groovy.json.JsonOutput as jo

def content = new File('response.json')
def slurper = new groovy.json.JsonSlurper()
def object = slurper.parseText(content)

def flattenMap(Map map) {
    def result = [:]

    map.each { k, v ->
        if (v instanceof Map) {
            result << flattenMap(v)
        } else if (v instanceof Collection && v.every {it instanceof Map}) {
            v.each {
                result << flattenMap(it)
            }
        } else {
            result[k] = v
        }
    }
    result
}

println(jo.prettyPrint(jo.toJson(flattenMap(object))))
导入groovy.json.JsonOutput作为jo
def content=新文件('response.json')
def slurper=new groovy.json.JsonSlurper()
def object=slurper.parseText(内容)
地图(地图地图){
def结果=[:]
map.each{k,v->
if(v instanceof Map){

结果解决此问题的一种方法如下:

[{
  "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
  "user_uid": 5467890,
  "article_id": 318153,
  "current_price_without_promo": 13.99,
  "promo_discount": 0,
  "count": 1,
  "apply_discount": true,
  "min_discount": 0,
  "max_discount": 8,
  "imposed_discount": null,
  "article_target_probability_increase": 1.15,
  "discount_downscale_factor": 1,
  "target_probability_increase": null,
  "request_time": "2019-12-21T21:32:13.018635",
  "total_discount": 0.94,
  "discount": 0.08
},
{
  "discount_guid": ...
},
...
]
import groovy.json.*

def str = '''
{
  "input_query": {
    "discount_guid": "3afeb169-7969-4f6f-8928-d801692848b1",
    "user_uid": 5467890,
    "shopping_list": [
      {
        "article_id": 311729,
        "current_price_without_promo": 7.69,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 229752,
        "current_price_without_promo": 11.29,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 193672,
        "current_price_without_promo": 79.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 261657,
        "current_price_without_promo": 16.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      },
      {
        "article_id": 318153,
        "current_price_without_promo": 13.99,
        "promo_discount": 0,
        "count": 1,
        "apply_discount": true
      }
    ],
    "discount_params_per_article": [
      {
        "article_id": 311729,
        "min_discount": 0,
        "max_discount": 4.12,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 229752,
        "min_discount": 0,
        "max_discount": 7.52,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 193672,
        "min_discount": 0,
        "max_discount": 60,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 261657,
        "min_discount": 0,
        "max_discount": 12.4,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      },
      {
        "article_id": 318153,
        "min_discount": 0,
        "max_discount": 8,
        "imposed_discount": null,
        "article_target_probability_increase": 1.15,
        "discount_downscale_factor": 1
      }
    ],
    "target_probability_increase": null,
    "request_time": "2019-12-21T21:32:13.018635"
  },
  "total_discount": 0.94,
  "article_discounts": [
    {
      "article_id": 311729,
      "discount": 0.04
    },
    {
      "article_id": 229752,
      "discount": 0.08
    },
    {
      "article_id": 193672,
      "discount": 0.61
    },
    {
      "article_id": 261657,
      "discount": 0.13
    },
    {
      "article_id": 318153,
      "discount": 0.08
    }
  ]
}
'''

def json = new JsonSlurper().parseText(str) 

// a predicate to check if a value is a plain value vs map or list
def isPlain     = { v -> !(v instanceof Map) && !(v instanceof List) }

// for the two maps json.input_query and the root level json map, 
// find all plain values
def plainValues = json.input_query.findAll { k, v -> isPlain(v) } +
                  json.findAll { k, v -> isPlain(v) } 

// find the three lists of maps, group by article_id and add the 
// values for each article id to a cumulative map and finally 
// add the plain values collected above to each cumulative map
def result = (json.input_query.shopping_list +
              json.input_query.discount_params_per_article +
              json.article_discounts).groupBy { 
                it.article_id 
              }.values().collect { listOfMaps -> 
                listOfMaps.sum() + plainValues
              }

// print result
result.each { m -> 
  println "-----"
  m.sort().each { k, v -> 
    println "${k.padLeft(35)} -> $v"
  }
}
执行上述操作将产生:

─➤ groovy solution.groovy
-----
                     apply_discount -> true
                         article_id -> 311729
article_target_probability_increase -> 1.15
                              count -> 1
        current_price_without_promo -> 7.69
                           discount -> 0.04
          discount_downscale_factor -> 1
                      discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
                   imposed_discount -> null
                       max_discount -> 4.12
                       min_discount -> 0
                     promo_discount -> 0
                       request_time -> 2019-12-21T21:32:13.018635
        target_probability_increase -> null
                     total_discount -> 0.94
                           user_uid -> 5467890
-----
                     apply_discount -> true
                         article_id -> 229752
article_target_probability_increase -> 1.15
                              count -> 1
        current_price_without_promo -> 11.29
                           discount -> 0.08
          discount_downscale_factor -> 1
                      discount_guid -> 3afeb169-7969-4f6f-8928-d801692848b1
                   imposed_discount -> null
                       max_discount -> 7.52
                       min_discount -> 0
                     promo_discount -> 0
                       request_time -> 2019-12-21T21:32:13.018635
        target_probability_increase -> null
                     total_discount -> 0.94
                           user_uid -> 5467890
-----
...
最后的打印输出按键排序,并进行一些缩进以提高可读性

然后,您可以使用如下方式获取输出json:

def outputJson = JsonOutput.toJson(result)

flatte
不是您的主要目标。您的主要目标似乎是迭代文章,并从父对象和其他同级对象收集所需信息,按文章id分组数据。我假设触发点是合并所有包含
artile\u id
的贴图和指向它们的贴图?除非您希望d您获得的数据和所有数据之间的差异将坚持这种方法您最好只在您知道的路径上提取数据。谢谢,这正是我所需要的。如果这解决了您的问题,最好将其标记为可接受的答案,这样其他人就不需要花时间重新解决您的问题。