代码之家  ›  专栏  ›  技术社区  ›  Eleanor

jq按特定键计算json中的项数

  •  23
  • Eleanor  · 技术社区  · 7 年前

    {
    "ReferringUrl": "N",
    "OpenAccess": "0",
    "Properties": {
        "ItmId": "1694738780"
       }
    }
    {
    "ReferringUrl": "L",
    "OpenAccess": "1",
    "Properties": {
        "ItmId": "1347809133"
      }
    }
    

    我想计算json中出现的每个ItmId的项数。例如,带有“ItmId”1694738780的项目在我的json文件中出现10次,带有“ItmId”1347809133的项目出现14次。然后返回这样的json

    {"ItemId": "1694738780",
     "Count":  10
    }
    {"ItemId": "1347809133",
     "Count":  14
    }
    

    我正在使用bash。更喜欢完全由jq来完成。但可以使用其他方法。

    4 回复  |  直到 6 年前
        1
  •  24
  •   peak    3 年前

    这里有一个解决方案(假设输入是有效的JSON对象流),您可以使用-s选项调用jq:

    map({ItemId: .Properties.ItmId})             # extract the ItmID values
    | group_by(.ItemId)                          # group by "ItemId"
    | map({ItemId: .[0].ItemId, Count: length})  # store the counts
    | .[]                                        # convert to a stream
    

    一种稍微节省内存的方法是使用 inputs 如果你的jq有;但是在这种情况下,使用-n而不是-s,并将上面的第一行替换为:[inputs |{ItemId:.Properties.ItmId}]

    上述解决方案使用内置 group_by ,这很方便,但容易避免效率低下。使用以下内容 counter

    def counter(stream):
      reduce stream as $s ({}; .[$s|tostring] += 1);
    

    使用-n命令行选项,并按如下方式应用:

    counter(inputs | .Properties.ItmId)
    

    {
      "1694738780": 1,
      "1347809133": 1
    }
    

    这样的字典可能比OP设想的单例对象流更有用,但如果需要这样的流,可以如下修改上述内容:

    counter(inputs | .Properties.ItmId)
    | to_entries[]
    | {ItemId: (.key), Count: .value}
    
        2
  •  15
  •   skr    7 年前

    cat json.txt | jq '.Properties .ItmId' | sort | uniq -c | awk -F " " '{print "{\"ItmId\":" $2 ",\"count\":" $1"}"}'| jq .
    
        3
  •  1
  •   peak    7 年前

    这是一个超级高效的解决方案——特别是,不需要排序。以下实现需要一个jq版本,带有 inputs 但是很容易将该程序调整为使用jq的早期版本。如果使用以下命令,请记住使用-n命令行选项:

    # Count the occurrences of distinct values of (stream|tostring).
    # To avoid unwanted collisions, or to recover the exact values,
    # consider using tojson
    def counter(stream):
      reduce stream as $s ({}; .[$s|tostring] += 1);
    
    counter(inputs | .Properties.ItmId)
    | to_entries[]
    | {ItemId: (.key), Count: .value}
    
        4
  •  1
  •   jq170727    7 年前

    这是一个变体,使用 减少 设置路径 获取路径 进行聚合和 to_条目

    jq --slurp -f query.jq < data.json
    

    data.json 包含您的数据和 包含

      map(.Properties.ItmId)
    | reduce .[] as $i (
        {}; setpath([$i]; getpath([$i]) + 1)
      )
    | to_entries | .[] | { "ItemId": .key, "Count": .value }