Hoe een array van objecten filteren op elementeigenschapswaarden met jq?

Ik filter graag json-bestanden met jq:

jq . some.json

Gezien de json die een reeks objecten bevat:

{
  "theList": [
    {
      "id": 1,
      "name": "Horst"
    },
    {
      "id": 2,
      "name": "Fritz"
    },
    {
      "id": 3,
      "name": "Walter"
    },
    {
      "id": 4,
      "name": "Gerhart"
    },
    {
      "id": 5,
      "name": "Harmut"
    }
  ]
}

Ik wil die lijst filteren om alleen de elementen weer te geven met id met de waarde 2 en 4, dus de verwachte output is:

{
  "id": 2,
  "name": "Fritz"
},
{
  "id": 4,
  "name": "Gerhart"
}

Hoe filter ik de json met jq? Ik heb wat met select en map gespeeld, maar ik heb geen van beide werkend gekregen, bijvoorbeeld:

$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json
true

Antwoord 1, autoriteit 100%

Uit de documenten:

jq '.[] | select(.id == "second")' 

Invoer[{"id": "first", "val": 1}, {"id": "second", "val": 2}]

Uitvoer{"id": "second", "val": 2}

Ik denk dat je zoiets als dit kunt doen:

jq '.theList[] | select(.id == 2 or .id == 4)' array.json

Antwoord 2, autoriteit 18%

Je zou selectkunnen gebruiken binnen map.

.theList | map(select(.id == (2, 4)))

Of compacter:

[ .theList[] | select(.id == (2, 4)) ]

Hoewel het op die manier is geschreven, is het een beetje inefficiënt omdat de uitdrukking wordt gedupliceerd voor elke waarde die wordt vergeleken. Op deze manier is het efficiënter en mogelijk beter leesbaar:

[ .theList[] | select(any(2, 4; . == .id)) ]

Antwoord 3, autoriteit 6%

Het gebruik van select(.id == (2, 4))hier is over het algemeen inefficiënt (zie hieronder).

Als uw jq IN/1heeft, kan deze worden gebruikt om een ​​efficiëntere oplossing te bereiken:

.theList[] | select( .id | IN(2,3))

Als uw jq geen IN/1heeft, kunt u deze als volgt definiëren:

def IN(s): first(select(s == .)) // false;

Efficiëntie

Een manier om de inefficiëntie te zien, is door debugte gebruiken. De volgende expressie resulteert bijvoorbeeld in 10 aanroepen voor debug, terwijl er eigenlijk maar 9 controles op gelijkheid nodig zijn:

.theList[] | select( (.id == (2,3)) | debug )
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
  "id": 2,
  "name": "Fritz"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
  "id": 3,
  "name": "Walter"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]

index/1

In principe zou het gebruik van index/1efficiënt moeten zijn, maar op het moment van schrijven (oktober 2017) is de implementatie ervan, hoewel snel (het is geschreven in C), inefficiënt.


Antwoord 4

Hier is een oplossing met behulp van indexen:

.theList | [ .[map(.id)|indices(2,4)[]] ]

Other episodes