简体   繁体   中英

How to target and count value with JQ?

From this file:

[
    {
        "network": "X.X.X.1",
        "defaultGateway": "X.X.X.X",
        "ipAddressTab": [
            {
                "foo1": "10.0.0.1",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
            },
            {
                "foo1": "10.0.0.2",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
            },
            {
                "foo1": "10.0.0.3",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
             },
             {
                "foo1": "10.0.0.4",
                "status": "available"
             },
             {   
                "foo1": "10.0.0.5",
                "status": "available"
             },
             {
                "foo1": "10.0.0.6",
                "status": "available"
             },
             {
                "foo1": "10.0.0.7",
                "status": "available"
             }
        ],
        "full": false,
        "id": "xxx"
    },
     {
        "network": "X.X.X.2",
        "defaultGateway": "X.X.X.X",
        "ipAddressTab": [
            {
                "foo1": "10.0.0.1",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
            },
            {
                "foo1": "10.0.0.2",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
            },
            {
                "foo1": "10.0.0.3",
                "foo2": "network",
                "status": "reserved",
                "foo4": null,
                "foo5": null,
                "foo6": null,
                "foo7": null,
                "foo8": null,
                "foo9": null,
                "foo10": null,
                "foo11": null
             },
             {
                "foo1": "10.0.0.4",
                "status": "available"
             },
             {   
                "foo1": "10.0.0.5",
                "status": "available"
             },
             {
                "foo1": "10.0.0.6",
                "status": "available"
             },
             {
                "foo1": "10.0.0.7",
                "status": "available"
             }
        ],
        "full": false,
        "id": "xxx"
    }
]

# Just an example, there is more lines in my file

I can keep the informations that I want:

cat myfile | jq 'map({network, full})'
[
  {
    "network": "X.X.X.1",
    "full": false
  },
  {
    "network": "X.X.X.2",
    "full": false
  }
]

Now I'm looking for a tip to count and display some values. For example, I would like to display the number of reserved, allocated and available like that:

[
  {
    "network": "X.X.X.1",
    "full": false
    reserved: 3
    available: 4

    

  },
  {
    "network": "X.X.X.2",
    "full": false
    reserved: 3
    available: 4

  }
]

I've look everywhere and I found no good example to do that...

Some one to show me how can I have this output?

Thanks !

Use reduce to count statuses.

map({network, full} +
  reduce .ipAddressTab[].status as $s ({}; .[$s] += 1))

Online demo

You can change {} to {reserved: 0, available: 0} to maintain a consistent order of keys among all the entries.

One way to do this would be to use a function to count the objects of each type

def f($path; $val): $path | map(select(.status == $val)) | length;
map({network, full, reserved: f(.ipAddressTab; "reserved"), available: f(.ipAddressTab; "available")})

jqplay - Demo

The function f takes a path and the status string to be looked-up then gets the length of the objects in the array.


With oguz ismail's suggestion to avoid repetition

def f($val): map(select(.status == $val)) | length; 
map({network, full} + (.ipAddressTab | { reserved: f("reserved"), available: f("available")}))

When counting a potentially large number of objects, it's usually better to use stream-oriented filters so as to avoid constructing arrays. These two are often useful as a pair, though in the present case defining just count/1 by itself would be sufficient:

def sigma(s): reduce s as $x (0; .+$x);

def count(s): sigma(s|1);

To achieve the stated goal, one can now simply write the specification as a program:


map({network,
    full,
    reserved:   count(.ipAddressTab[] | select(.status == "reserved")),
    available:  count(.ipAddressTab[] | select(.status == "available"))
    })

Generalization

Now for a little jq magic -- no references to specific "status" values at all:

def countStatus($s):
  {($s): count(.ipAddressTab[] | select(.status == $s))};

def statuses: [.ipAddressTab[].status] | unique;

map( {network, full}
     + ([countStatus(statuses[])] | add) )

total_available

In a comment, a question about showing total_available was asked. To add a total_available key to each object, you could append the following to either of the above pipelines:

| {total_available: sigma(.[] | .available)} as $total
| map(. + $total)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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