使用jq对json文件进行排序和过滤

时间:2017-08-16 04:47:33

标签: json grouping jq

我试图解析一个json文件,以便为artifactory实例创建一个删除列表。

我喜欢用两个字段对它们进行分组:repo和path。然后保留每个分组的两个对象与最近的"修改" timestamp并删除json文件中的所有其他对象。

所以,原始文件看起来像这样:

{
  "results": [
    {
      "repo": "repo1",
      "path": "docker_image_dynamic",
      "size": 3624,
      "modified": "2016-10-01T06:22:16.335Z"
    },
    {
      "repo": "repo1",
      "path": "docker_image_dynamic",
      "size": 3646,
      "modified": "2016-10-01T07:03:58.465Z"
    },
    {
      "repo": "repo1",
      "path": "docker_image_dynamic",
      "size": 3646,
      "modified": "2016-10-01T07:06:36.522Z"
    },
    {
      "repo": "repo2",
      "path": "docker_image_static",
      "size": 3624,
      "modified": "2016-09-29T20:31:44.054Z"
    }
  ]
}

应该成为这个:

{
  "results": [
    {
      "repo": "repo1",
      "path": "docker_image_dynamic",
      "size": 3646,
      "modified": "2016-10-01T07:03:58.465Z"
    },
    {
      "repo": "repo1",
      "path": "docker_image_dynamic",
      "size": 3646,
      "modified": "2016-10-01T07:06:36.522Z"
    },
    {
      "repo": "repo2",
      "path": "docker_image_static",
      "size": 3624,
      "modified": "2016-09-29T20:31:44.054Z"
    }
  ]
}

4 个答案:

答案 0 :(得分:2)

这应该这样做:

.results |= [group_by({repo,path})[] | sort_by(.modified)[-2:][]]

repopath对数组中的项目进行分组后,按modified对组进行排序,并保留已排序组的最后两项。然后再次拆分组并将它们收集到一个新阵列中。

答案 1 :(得分:1)

这是一个更麻烦的解决方案,它使用 reduce 来维护一个临时对象,其中包含每个repopath的最后两个值。除非输入包含(repo,path)的每个组合的大量条目,否则它可能不会比Jeff的解决方案更好:

    {
      results: [
        reduce .results[] as $r (
             {}                                 # temporary object
           ; (
                getpath([$r.repo, $r.path])     # keep the latest two
              | . + [$r]                        # elements for each
              | sort_by(.modified)[-2:]         # repo and path in a
             ) as $new                          # temporary object
           | setpath([$r.repo, $r.path]; $new)  #
        )
        | .[] | .[] | .[]                       # extract saved elements
      ]
    }

答案 2 :(得分:1)

@ jq170727对使用group_by的潜在低效率提出了一个很好的观点,因为group_by涉及排序。在实践中,排序可能太快而无关紧要,但如果关注,我们可以非常轻松地定义我们自己的无排序版本group_by

# sort-free variant of group_by/1
# f must always evaluate to a string.
# Output: an object
def GROUP_BY(f): reduce .[] as $x ({}; .[$x|f] += [$x] );

@ JeffMercado的解决方案现在可以在tojson的帮助下使用,如下所示:

.results |= [GROUP_BY({repo,path}|tojson)[] | sort_by(.modified)[-2:][]]

GROUP_BY / 2

为了避免调用tojson,我们可以调整以上内容以产生以下更快的解决方案:

def GROUP_BY(f;g): reduce .[] as $x ({}; .[$x|f][$x|g] += [$x]);

.results |= [GROUP_BY(.repo;.path)[][] | sort_by(.modified)[-2:][]]

答案 3 :(得分:1)

除了评论之外,这里有一个更简洁(更jq-esque(*))的方式来表达@ jq170727的解决方案:

.results |= [reduce .[] as $r ( {};
               .[$r.repo][$r.path] |= ((.+[$r]) | sort_by(.modified)[-2:])) 
             | .[][]]

(*)特别没有getpath,setpath或$ new;并且|=减少了冗余。