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í .