¿Cómo filtrar una matriz de objetos basada en valores en una matriz interna con jq?

Teniendo en cuenta esta entrada:

[ { "Id": "cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b", "Names": [ "condescending_jones", "loving_hoover" ] }, { "Id": "186db739b7509eb0114a09e14bcd16bf637019860d23c4fc20e98cbe068b55aa", "Names": [ "foo_data" ] }, { "Id": "a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19", "Names": [ "jovial_wozniak" ] }, { "Id": "76b71c496556912012c20dc3cbd37a54a1f05bffad3d5e92466900a003fbb623", "Names": [ "bar_data" ] } ] 

Estoy intentando construir un filtro con jq que devuelve todos los objetos con Id s que no contienen “datos” en la matriz de Names internos, con la salida separada por línea nueva. Para los datos anteriores, el resultado que me gustaría es

 cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19 

Creo que estoy algo cerca de esto:

 (. - select(.Names[] contains("data"))) | .[] .Id 

pero el filtro de select no es correcto y no se comstack (obtener error: syntax error, unexpected IDENT ).

¡Muy cerca! En su expresión de select , debe usar una tubería ( | ) antes de contains .

Este filtro produce la salida esperada.

 . - map(select(.Names[] | contains ("data"))) | .[] .Id 

El libro de cocina jq tiene un ejemplo de la syntax.

Filtrar objetos en función del contenido de una clave

Por ejemplo, solo quiero objetos cuya clave de género contenga “casa”.

 $ json='[{"genre":"deep house"}, {"genre": "progressive house"}, {"genre": "dubstep"}]' $ echo "$json" | jq -c '.[] | select(.genre | contains("house"))' {"genre":"deep house"} {"genre":"progressive house"} 

Colin D pregunta cómo preservar la estructura JSON de la matriz, de modo que la salida final sea una única matriz JSON en lugar de una secuencia de objetos JSON.

La forma más sencilla es envolver toda la expresión en un constructor de matriz:

 $ echo "$json" | jq -c '[ .[] | select( .genre | contains("house")) ]' [{"genre":"deep house"},{"genre":"progressive house"}] 

También puedes usar la función de mapa:

 $ echo "$json" | jq -c 'map(select(.genre | contains("house")))' [{"genre":"deep house"},{"genre":"progressive house"}] 

map descomprime la matriz de entrada, aplica el filtro a cada elemento y crea una nueva matriz. En otras palabras, el map(f) es equivalente a [.[]|f] .

Aquí hay otra solución que usa any / 2

 map(select(any(.Names[]; contains("data"))|not)|.Id)[] 

con los datos de muestra y la opción -r que produce

 cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19 
    Intereting Posts