J'aime filtrer les fichiers json avec jq :
jq . some.json
Étant donné le json contenant un tableau d'objets:
{
"theList": [
{
"id": 1,
"name": "Horst"
},
{
"id": 2,
"name": "Fritz"
},
{
"id": 3,
"name": "Walter"
},
{
"id": 4,
"name": "Gerhart"
},
{
"id": 5,
"name": "Harmut"
}
]
}
Je souhaite filtrer cette liste pour ne montrer que les éléments dont l'id a la valeur 2 et 4, le résultat attendu est donc:
{
"id": 2,
"name": "Fritz"
},
{
"id": 4,
"name": "Gerhart"
}
Comment filtrer le json avec jq? J'ai joué avec select and map, mais aucun de ceux-ci n'a fonctionné, par exemple:
$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json
true
À partir de la documentation:
jq '.[] | select(.id == "second")'
Entrée
[{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Sortie
{"id": "second", "val": 2}
Je pense que vous pouvez faire quelque chose comme ça:
jq '.theList[] | select(.id == 2 or .id == 4)' array.json
Vous pouvez utiliser select
dans map
.
.theList | map(select(.id == (2, 4)))
Ou plus compact:
[ .theList[] | select(.id == (2, 4)) ]
Bien qu'écrit de cette façon est un peu inefficace car l'expression est dupliquée pour chaque valeur comparée. Ce sera plus efficace et peut-être plus lisible, écrit de cette façon:
[ .theList[] | select(any(2, 4; . == .id)) ]
Utiliser select(.id == (2, 4))
ici est généralement inefficace (voir ci-dessous).
Si votre jq a IN/1
, alors il peut être utilisé pour obtenir une solution plus efficace:
.theList[] | select( .id | IN(2,3))
Si votre jq n'a pas IN/1
, vous pouvez le définir comme suit:
def IN(s): first(select(s == .)) // false;
Efficacité
Une façon de voir l'inefficacité consiste à utiliser debug
. L'expression suivante, par exemple, entraîne 10 appels à debug
, alors que seulement 9 contrôles d'égalité sont réellement nécessaires:
.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
En principe, utiliser index/1
devrait être efficace, mais à ce jour (octobre 2017), sa mise en œuvre, bien que rapide (elle est écrite en C), est inefficace.
Voici une solution utilisant indices :
.theList | [ .[map(.id)|indices(2,4)[]] ]