tidwall / gjson

Get JSON values quickly - JSON parser for Go
MIT License
14.21k stars 847 forks source link

Filtering on count #265

Closed ccakes closed 2 years ago

ccakes commented 2 years ago

First up - nice library! :+1:

This might be pushing it a little but is it possible to filter an object based on the count of a query result? Basically I'm trying to filter some JSON fetched from a Jira instance to only return issues with a certain number of matching labels... an example will help

{
  "issues": [
    {
      "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields",
      "fields": {
        "labels": [
          "milestone_1",
          "group:foo",
          "plan:a",
          "plan:b"
        ],
        "summary": "Do some stuff"
      },
      "id": "123",
      "key": "PROJ-1"
    }
  ]
}

Basically I want to filter for issues where the issue has > 2 labels containing plan:*. I've got this query which lets me target the labels but I can't figure out how to then only return the issues where the count of the inner query is >2.

issues.#(fields.labels.#(%"plan:*"))#

I've read the docs and tried the obvious suspect (eg |#>2 and .#>2) but no luck. Any tips? Or is this more of a job for jq?

tidwall commented 2 years ago

I think the problem is that gjson can get the number of plans, and it can get the ids, but it can't easily associate the two to filter on.

I used the following json to test with on https://gjson.dev:

{
  "issues": [ {
    "fields": { "labels": [ "plan:a", "plan:b" ] },
    "id": "123"
  },{
    "fields": { "labels": [ "plan:c" ] },
    "id": "456"
  }]
}

Get the ids:

issues.#.id
["123","456"]

Get number of plans:

issues.#.fields.labels.#(%"plan:*")#|#.#
[2,1]

Combine into an object:

{"id":issues.#.id,"plans":issues.#.fields.labels.#(%"plan:*")#|#.#}
{"id":["123","456"],"plans":[2,1]}

But that's as far as I could get.

So I added a new modifier @group which will group the results like such:

{"id":issues.#.id,"plans":issues.#.fields.labels.#(%"plan:*")#|#.#}|@group
[{"id":"123","plans":2},{"id":"456","plans":1}]

And then I added a query to the end to filter out

{"id":issues.#.id,"plans":issues.#.fields.labels.#(%"plan:*")#|#.#}|@group|#(plans>1)#.id
["123"]

This seems to work 😅. Check out the new v1.14.0 which includes @group.

ccakes commented 2 years ago

You're a legend! Thanks so much!