json - query - map javascript
¿Cómo filtrar una matriz de objetos por valores de propiedades de elementos usando jq? (4)
Me gusta filtrar archivos json usando jq :
jq . some.json
Dado el json que contiene una matriz de objetos:
{
"theList": [
{
"id": 1,
"name": "Horst"
},
{
"id": 2,
"name": "Fritz"
},
{
"id": 3,
"name": "Walter"
},
{
"id": 4,
"name": "Gerhart"
},
{
"id": 5,
"name": "Harmut"
}
]
}
Quiero filtrar esa lista para mostrar solo los elementos con id que tienen el valor 2 y 4, por lo que la salida esperada es:
{
"id": 2,
"name": "Fritz"
},
{
"id": 4,
"name": "Gerhart"
}
¿Cómo puedo filtrar el json usando jq? He jugado con selección y mapa, pero no conseguí que ninguno de ellos funcionara, por ejemplo:
$ jq ''.theList[] | select(.id == 2) or select(.id == 4)'' array.json
true
Aquí hay una solución utilizando indices :
.theList | [ .[map(.id)|indices(2,4)[]] ]
El uso de la select(.id == (2, 4))
aquí es generalmente ineficiente (ver más abajo).
Si su jq tiene IN/1
, entonces puede usarse para lograr una solución más eficiente:
.theList[] | select( .id | IN(2,3))
Si su jq no tiene IN/1
, entonces puede definirlo de la siguiente manera:
def IN(s): first(select(s == .)) // false;
Eficiencia
Una forma de ver la ineficiencia es utilizar la debug
. La siguiente expresión, por ejemplo, da como resultado 10 llamadas a debug
, mientras que solo se necesitan 9 comprobaciones de igualdad:
.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]
índice / 1
En principio, el uso de index/1
debe ser eficiente, pero a partir de este escrito (octubre de 2017), su implementación, aunque rápida (está escrito en C), es ineficiente.
Podrías usar select
dentro del map
.
.theList | map(select(.id == (2, 4)))
O más compacto:
[ .theList[] | select(.id == (2, 4)) ]
Aunque escrito de esta manera es un poco ineficiente ya que la expresión se duplica para cada valor que se compara. Será más eficiente y posiblemente más legible escrito de esta manera:
[ .theList[] | select(any(2, 4; . == .id)) ]
De los documentos:
jq ''.[] | select(.id == "second")''
Introduzca
[{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Salida
{"id": "second", "val": 2}
Creo que puedes hacer algo como esto:
jq ''.theList[] | select(.id == 2 or .id == 4)'' array.json