Tengo un objeto json complejo guardado en una base de datos postgresql y quiero encontrar todas las entradas que contienen o comienzan con una subcadena dentro de una matriz. El objeto json:
"configurations" : { "CVE_data_version" : "4.0", "nodes" : [ { "operator" : "OR", "cpe_match" : [ { "vulnerable" : true, "cpe23Uri" : "cpe:2.3:a:apache:http_server:*:*:*:*:*:*:*:*", "versionStartIncluding" : "2.4.0", "versionEndIncluding" : "2.4.41" } ] } ] }
Más específicamente, quiero encontrar todos los objetos que comienzan con: "cpe:2.3:a:apache" en el campo "cpe23Uri".
Consulta que he hecho:
session.query(cvemodel.data['configurations']['nodes'][0]['cpe_match'].contains([{'cpe23Uri': 'cpe:2.3:a:apache:http_server:*:*:*:*:*:*:*:*'}])).all()
El problema con esta consulta es que coincide con la palabra completa. Si pongo esto:
session.query(cvemodel.data['configurations']['nodes'][0]['cpe_match'].contains([{'cpe23Uri': 'cpe:2.3:a:apache:http_server'}])).first()
¡No devuelve nada!
Si usa PostgreSQL 12 o posterior, puede usar jsonb_path_exists()
y amigos:
needle = 'cpe:2.3:a:apache:http_server' session.query(cvemodel).\ filter(func.jsonb_path_exists( cvemodel.data, '''$.configurations.nodes[0].cpe_match[*].cpe23Uri ? (@ starts with $needle)''', json.dumps({"needle": needle}))).\ all()
Si desea verificar si cpe23Uri
contiene la aguja, puede usar el predicado like_regex
, especialmente si tiene una "aguja" estática; desafortunadamente like_regex
solo acepta cadenas literales como operando derecho. Otra opción para una consulta "contiene" sería extraer el cpe23Uri
usando jsonb_path_query()
o accesores y jsonb_array_elements()
y usar LIKE
tradicional, como se describe aquí .