jq: count nest object values which satisfy conditi

2019-09-14 23:15发布

json data:

{testId: '1' studentId:{'s1':{score: 20} 's2':{score: 80}}}
{testId: '2' studentId:{'s1':{score: 60} 's2':{score: 70}}}
{testId: '3' studentId:{'s5':{score: 40} 's7':{score: 30}}}
...

I would like to use JQ to tell me how many students achieved a score > x, for each test.

Thus for the above input and x = 50, the output:

{testId: '1' numStudents:1}
{testId: '2' numStudents:2}
{testId: '3' numStudents:0}

I am able to generate a list of all students who achieved > 50 on each test with

{testId, studentId: .studentId[]?} | select(.studentId.score>50)

This command creates a list of objects where each object contains testId, studentId and score, where all scores are greater than 50. However I do not know how to recombine these results into the output I want.

1条回答
唯我独甜
2楼-- · 2019-09-14 23:50

The following assumes the input consists of a stream of valid JSON objects.

One approach is to use add:

$ jq '{testId, numStudents: ([select(.studentId[].score > 50) | 1] | add // 0)}' 

With the given input (after corrections have been made), the output would be:

{ "testId": "1", "numStudents": 1 } { "testId": "2", "numStudents": 2 } { "testId": "3", "numStudents": 0 }

An alternative would be to use length, e.g. with this filter:

{testId,
 numStudents: ([select(.studentId[].score > 50) ] | length)}

However, if you don't mind adding a 'def', then the best solution (e.g. because it does not involve construction of an intermediate array) would be along the following lines:

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

{testId, numStudents: count(select(.studentId[].score > 50))} 
查看更多
登录 后发表回答