Filtrar arrays es el punto en el que JSONPath deja de ser un simple truco de navegación y se convierte en un lenguaje de consulta realmente útil. Seleccionar $.users[*].email es fácil. Lo valioso es quedarse solo con usuarios activos, pedidos por encima de un umbral, eventos de una región concreta u objetos que siquiera contienen un campo. Ahí es donde entran en juego los filtros.
Esta guía se centra exclusivamente en filtros prácticos de JSONPath. Usaremos estructuras realistas, veremos dónde funcionan bien y explicaremos por qué algunas implementaciones antiguas todavía pueden sorprenderte. Si antes quieres repasar toda la sintaxis, mira nuestra guía de sintaxis JSONPath. Y si quieres comparar JSONPath con otros lenguajes, sigue después con la comparativa JSONPath vs JMESPath.
La Forma Básica del Filtro
Un filtro JSONPath suele escribirse dentro de un selector de array como [?(...)]. La expresión entre paréntesis se evalúa contra cada elemento del array. El símbolo @ representa el elemento actual. En una lista simple de productos, $.products[?(@.price < 100)] devuelve únicamente los productos cuyo precio está por debajo de 100.
Ese patrón básico cubre la mayor parte del uso real. Lo que cambia de ejemplo en ejemplo es la ruta del campo, el operador de comparación y si filtras por valor, por existencia o por una propiedad anidada. La manera más rápida de dominar JSONPath es aprender bien esas formas recurrentes.
Ejemplo 1: Filtros de Igualdad
Supongamos que una API devuelve usuarios con roles y estados. Para quedarte solo con administradores, puedes usar una igualdad directa como $.users[?(@.role == 'admin')]. Para quedarte solo con registros activos, usarías $.users[?(@.active == true)]. Los filtros de igualdad son la mejor puerta de entrada porque se leen casi como lenguaje natural: “devuélveme los elementos cuyo campo es igual a este valor”.
La lección práctica es respetar el tipo JSON real. Si el payload guarda true como booleano, compararlo con la cadena 'true' no producirá lo que esperas. Lo mismo ocurre con valores numéricos. Un buen flujo consiste en formatear primero el JSON con nuestro formateador JSON, verificar los tipos y luego escribir el filtro.
Ejemplo 2: Comparaciones Numéricas
Los filtros numéricos son habituales en dashboards, APIs de facturación, gestión de pedidos y monitorización. Un selector como $.orders[?(@.total >= 500)] devuelve solo pedidos de importe alto. Otro como $.metrics[?(@.latencyMs < 200)] se queda con respuestas rápidas. Operadores como <, <=, > y >= hacen que JSONPath resulte muy útil para extraer subconjuntos basados en umbrales.
El problema típico aquí es la calidad de datos. Muchos sistemas serializan números como cadenas. Si una API devuelve "500" y otra devuelve 500, un filtro copiado de una a otra puede dejar de funcionar. Cuando alguien dice que JSONPath es “poco fiable”, muchas veces el problema está en el tipado inconsistente del JSON, no en el lenguaje.
Ejemplo 3: Filtrar por Campos Anidados
Los payloads reales rara vez son planos. Puede que necesites filtrar un array de clientes por address.country o un array de servicios por health.status.code. JSONPath lo permite siguiendo la ruta anidada dentro del filtro: $.customers[?(@.address.country == 'ES')] o $.services[?(@.health.status.code == 200)].
Aquí es donde los filtros se vuelven especialmente valiosos en testing de APIs. Puedes reducir una respuesta grande a los pocos objetos que incumplen una regla concreta en lugar de revisar todo el documento a mano. En depuración, ese ahorro de tiempo suele marcar la diferencia entre dos minutos y una búsqueda frustrante de veinte.
Ejemplo 4: Comprobaciones de Existencia
A veces no te importa todavía el valor. Solo quieres saber si el campo existe. En ese caso, un filtro como $.users[?(@.email)] selecciona objetos que contienen un campo email con un valor interpretable como presente. Esto es útil con campos opcionales, esquemas en migración o eventos semiestructurados donde algunos productores emiten un campo y otros no.
Las comprobaciones de existencia son muy útiles, pero conviene interpretarlas con cuidado. Según la implementación y la expresión concreta, null, cadena vacía y campo ausente no siempre se tratan exactamente igual. Si tu control de calidad depende de esa diferencia, conviene validarlo con la librería real que vas a usar.
Ejemplo 5: Condiciones Combinadas
En producción es muy normal encadenar varias reglas. Tal vez quieras suscripciones activas en Europa con valor mensual por encima de cierto importe. Una expresión como $.subscriptions[?(@.active == true && @.region == 'EU' && @.monthlyValue > 50)] lo resume en una sola consulta. Aquí JSONPath deja de ser un selector sencillo y se convierte en una herramienta operativa de verdad.
La recomendación es no volverse demasiado ingenioso. Si el filtro cuesta leerlo, también costará confiar en él durante una incidencia. En esos casos quizá convenga dividir la consulta, normalizar antes el JSON o comparar snapshots con nuestra herramienta JSON diff.
Ejemplo 6: Arrays Dentro de Arrays
Muchas APIs modernas anidan arrays dentro de objetos superiores: pedidos con líneas, dashboards con widgets, usuarios con roles, repositorios con etiquetas. La técnica habitual es navegar primero al array interior y filtrar allí. Por ejemplo, $.orders[*].items[?(@.quantity > 10)] permite detectar líneas de pedido inusualmente grandes en todos los pedidos.
Este patrón es potente, pero también fácil de malinterpretar porque el resultado puede ser una colección de coincidencias procedentes de muchos objetos padre distintos. Por eso conviene mirar tanto el valor como la ruta completa. Esa es una de las razones por las que nuestra herramienta JSONPath muestra ambas cosas.
Ejemplo 7: Logs, Eventos y Errores de API
Los filtros también son ideales para observabilidad y soporte. Un payload como $.events[?(@.level == 'error')] aísla solo los eventos de error. Otro como $.logs[?(@.service == 'billing' && @.status >= 500)] reduce una respuesta ruidosa a los fallos que realmente importan. En operaciones y soporte, ese paso de “algo falla” a “estos son los cinco objetos rotos” es justo lo que hace que JSONPath merezca la pena.
Este tipo de uso también deja claro el límite del lenguaje: JSONPath sirve para extraer, no para remediar. Una vez identificados los elementos problemáticos, podrás compararlos, validarlos o parchearlos en otras herramientas. JSONPath te lleva muy rápido a la parte del documento que sí merece atención.
Errores Habituales
El primer error frecuente es comparar tipos distintos: números como cadenas, booleanos como texto o null confundido con ausencia. El segundo es asumir que todas las librerías soportan la misma semántica de filtros, sobre todo en runtimes viejos. El tercero es intentar meter demasiada lógica en una sola expresión. Si cuesta leer la consulta, costará depurarla.
Una buena práctica es trabajar por etapas. Primero selecciona el array. Luego confirma una ruta simple. Después añade una condición. Y solo al final combina varias. Ese enfoque incremental detecta antes los fallos que pegar un filtro complejo y adivinar por qué no devuelve nada.
Conclusión
Si dominas igualdad, umbrales numéricos, campos anidados, comprobaciones de existencia y predicados combinados, ya conoces casi todo lo que hace útil a JSONPath en situaciones reales. El lenguaje es valioso no por ser teóricamente enorme, sino porque permite aislar exactamente las filas que importan dentro de respuestas JSON complejas.
Para el trabajo diario, mantén los filtros explícitos, verifica antes los tipos del input y desconfía de las consultas demasiado amplias. Después prueba tus expresiones en nuestra herramienta JSONPath antes de llevarlas a CI, tests de API o diagnósticos de producción.
Cómo Depurar un Filtro que no Devuelve Nada
Un resultado vacío no significa automáticamente que la condición esté mal. Muchas veces el fallo está antes, en la ruta. Empieza seleccionando el array sin filtros y confirma que realmente contiene los objetos esperados. Luego selecciona el campo que vas a comparar y revisa su tipo y su nombre. Solo después añade el predicado. Este enfoque por etapas es más rápido que reescribir toda la expresión porque aísla si el problema está en la navegación, en el tipado de los datos o en la sintaxis del filtro.
También ayuda probar contra el payload real que existirá en producción. Muchos ejemplos funcionan con datos limpios y fallan con respuestas reales porque hay campos opcionales, arrays con objetos heterogéneos o servicios que serializan números y booleanos de forma inconsistente. Un buen filtro es el que sobrevive a la variación real del JSON, no solo el que pasa en el ejemplo más bonito.
Una Regla de Portabilidad para Equipos
Si un filtro va a copiarse entre herramientas, conviene mantenerlo conservador. Prioriza comparaciones directas, comprobaciones de propiedades anidadas y tests booleanos claros en lugar de expresiones demasiado ingeniosas que dependan de una sola librería. Guarda además uno o dos payloads de ejemplo junto con la consulta para que cualquier persona pueda verificar la salida esperada en otro runtime. Ese hábito vale mucho cuando el mismo selector termina en navegador, tests de API, validaciones backend y cuadernos de incident response.
Dicho de otra forma, los filtros JSONPath más útiles no son solo correctos. Son reproducibles, legibles y fáciles de volver a probar meses después. Ese es el estándar que merece la pena perseguir cuando los filtros pasan de ser un truco puntual a formar parte de un flujo operativo.