Home > Mobile >  bash shell script jq Get a field and make statistics
bash shell script jq Get a field and make statistics

Time:11-23

I want to count the number of "domains" for which "adminLock" is equal to 1.

This is my json data structure:

{
  "code": 0,
  "message": "成功",
  "data": {
    "recordCount": "128",
    "pageSize": 100,
    "page": 1,
    "pageCount": 2,
    "data": [
      {
        "domainsID": "173652434",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome1.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 0,
        "view_type": "1"
      },
      {
        "domainsID": "173205836",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome2.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 1,
        "view_type": "1"
      },
      {
        "domainsID": "173205812",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome3.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 0,
        "view_type": "1"
      },
      {
        "domainsID": "173203610",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome4.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 1,
        "view_type": "1"
      },
      {
        "domainsID": "173203210",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome5.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 1,
        "view_type": "1"
      },
      {
        "domainsID": "173203131",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome6.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 1,
        "view_type": "1"
      },
      {
        "domainsID": "173203074",
        "nsGroupID": "199",
        "groupID": "78987",
        "domains": "dome7.com",
        "state": 3,
        "userLock": 0,
        "adminLock": 1,
        "view_type": "1"
      }
    ],
    "nextPage": 2
  }
}

Here's what I have so far:

'.data.data[] | select(.adminLock == 1) | .domains'

I can get the value of .domains, but how can I count how many times it occurs?

Replenish

The script I am using is the bash shell This command gets the value, I want to count the domains value in the case of adminLock=1, and count the number of domains ———————— Judging that adminLock=1 is getting the domains value, and counting how many in total

CodePudding user response:

To have a single count of all resulting items, either make an array and determine its length:

.data.data | map(select(.adminLock == 1)) | length
5

Demo

Or iterate and count, e.g. using reduce:

reduce (.data.data[] | select(.adminLock == 1)) as $i (0; . 1)
5

Demo

The first approach may seem more "natural" but it actually builds up an array that you eventually may not need. Therefore, if you only need the count, not the items themselves, use the second approach.


To count the items based on a certain property, say, the distinct values of .domains, create an according structure and count as shown before. The array approach could group the items using group_by:

.data.data | map(select(.adminLock == 1)) | group_by(.domains)
| map("\(first.domains): \(length)") # create your desired format
[
  "dome2.com: 1",
  "dome4.com: 1",
  "dome5.com: 1",
  "dome6.com: 1",
  "dome7.com: 1"
]

Demo

The iterative approach successively builds up your output structure, e.g. an object with the property as field names:

reduce (.data.data[] | select(.adminLock == 1)) as $i (
  {}; .[$i.domains]  = 1 # create your desired format
)
{
  "dome2.com": 1,
  "dome4.com": 1,
  "dome5.com": 1,
  "dome6.com": 1,
  "dome7.com": 1
}

Demo

CodePudding user response:

In general, rather than constructing an array, it's better to use a stream-oriented counting method:

def count(s): reduce s as $x (0;. 1);

In your case, it seems you could get away with:

count(.data.data[] | select(.adminLock == 1))

but perhaps you would want to check there is a domains key:

count(.data.data[] | select(.adminLock == 1 and has("domains") ))

If, however, you want to count the number of distinct domains satisfying the condition, it would probably be simplest to use unique:

[.data.data[] | select(.adminLock == 1) | .domains] | unique | length

But it's not hard to write a stream-oriented version of unique to avoid having to call unique/0 ...

  • Related