Repository navigation
GOQL.es
🌐 English · Deutsch · Français · 简体中文
Cada vista de lista de Gramps Connect (Personas, Familias, Eventos, etc.) tiene un cuadro de búsqueda. Por defecto, escribir en él hace una coincidencia rápida de texto simple sobre unos pocos campos comunes de esa vista (para Personas: ID de Gramps y nombre; para Lugar: ID, título y nombre del lugar; etc.), suficiente para la mayoría de las búsquedas cotidianas, y es el comportamiento por defecto porque es más sencillo que un lenguaje de consulta.
Junto al cuadro hay una casilla: «Usar Gramps Object Query Language». Actívela y ese mismo cuadro acepta en cambio una condición GOQL completa (gramps-object-query-language): un pequeño lenguaje creado específicamente para consultar registros de Gramps, capaz de cosas que la coincidencia de texto simple no puede ni rozar: recorrer relaciones (una unión o join, en términos de bases de datos: «todas las familias en las que la madre y el padre comparten apellido») e incluso recorrerlas hacia atrás («todas las notas a las que ya nada apunta»). Esta página es para cualquiera que quiera escribir una de esas condiciones; no hace falta experiencia en programación.
GOQL es también lo que hay detrás de las llamadas filter()/db. get_number_of() de los Gramplets y del argumento where= de
people()/families()/etc.: la misma sintaxis que escribiría en el
cuadro de búsqueda con la casilla activada también funciona desde el
código Python de un complemento. (db.get_number_of() y el antiguo
count() a secas son funciones de la API de Gramplets para contar
registros coincidentes, no el any/len propio de GOQL que se explica
más abajo: cosas distintas con el mismo nombre.)
¿No quiere escribirlo a mano en absoluto? El botón «Filtros» junto al título de cada lista ofrece decenas de reglas comunes como simples casillas (combinables con AND/OR, anidables y negables) y construye exactamente el mismo GOQL por debajo, mostrado en solo lectura para que vea lo que ha escrito. Consulte la lista de funciones de la página Descripción general para más detalles. Su «+ Nueva regla personalizada…» es el único lugar dentro de ese diálogo que todavía acepta una condición GOQL escrita a mano, con la misma sintaxis que toda esta página; una vez guardada y con nombre, se reutiliza como una casilla normal a partir de entonces, sin volver a escribirla nunca.
Una consulta siempre se escribe en el contexto de una vista (Persona, Familia, Evento, etc.) y es solo una condición:
surname == 'Smith'Se lee así: en la vista Personas, buscar los registros cuyo apellido sea igual a 'Smith'. La vista en la que busca determina a qué tipo de registro se aplica la condición.
Unos pocos símbolos aparecen una y otra vez:
| Símbolo | Significa |
|---|---|
==, !=
|
es igual a / no es igual a |
<, <=, >, >=
|
es menor que, como máximo, mayor que, como mínimo (anterior/posterior, más pequeño/más grande) |
and, or, not
|
combinan condiciones, o invierten una |
in [ ... ] |
coincide con cualquiera de una lista de valores |
'text' in field |
coincide si field contiene 'text' en cualquier parte |
like(field, 'pattern') |
coincide con un patrón de texto, donde % significa «cualquier cosa» |
regex(field, 'pattern') |
coincide con una expresión regular, para quienes ya las conocen |
Los valores de texto van entre comillas simples ('Smith'); los números
no (1968).
and exige que ambos lados sean verdaderos; or solo necesita uno.
Ambos se leen con naturalidad: gender == Person.MALE and surname == 'Smith' encuentra a todos los hombres apellidados Smith, mientras que
given_name == 'John' or surname == 'Doyle' encuentra a todos los
llamados John o a cualquiera apellidado Doyle. Mezclar ambos funciona
igual que en la aritmética corriente, donde la multiplicación se hace
antes que la suma (and se evalúa antes que or), pero los paréntesis
dejan clara la intención en cualquier caso: (gender == Person.MALE and surname == 'Smith') or given_name == 'Mary' encuentra a todos los
varones Smith, más a cualquiera llamada Mary, sea del sexo que sea.
not invierte una condición y coincide siempre que lo que contiene no
sea verdadero: not (surname == 'Smith') son todas las personas cuyo
apellido no es Smith. Las comparaciones también se pueden encadenar, como
permite el Python real: Date('Jan 1, 1900') < birth.date.sortval < Date('Jan 1, 1950') encuentra a todas las personas nacidas estrictamente
entre esas dos fechas, en una línea en lugar de dos unidas con and.
Además del == simple, unas cuantas formas más flexibles de comparar
texto cubren la mayoría de las búsquedas cotidianas. given_name in ['John', 'Jane'] coincide con cualquier nombre de la lista; añada tantos
como quiera. 'an' in given_name coincide en cualquier parte del nombre
(Jane, Alexander, Susan, ...) sin necesidad de comodines. like(field, 'J%') coincide con un patrón en el que % significa «cualquier cosa»,
así que like(given_name, 'J%') coincide con John, Jane, James, etc.
Para quien ya se maneje con expresiones regulares, regex(field, 'pattern') es aún más potente: regex(surname, '^[SD]') encuentra de
una vez a todos los Smith y Doyle, algo que like(...) no puede expresar
sin escribir una condición aparte para cada letra inicial.
Un campo no tiene por qué estar directamente en el registro que está
buscando. birth y death van de una persona a su evento de nacimiento o
de defunción, así que birth.date.sortval es la fecha de ese evento, y
birth.place.title da un paso más, hasta el lugar de ese evento. La misma
idea funciona con otros tipos de registro: father y mother van de una
familia al registro Persona de cada progenitor (father.surname == 'Smith'), source va de una cita a lo que cita, y enclosed_by va de un
lugar al lugar que lo contiene (el condado de una ciudad, por ejemplo; y
se encadena consigo mismo, así que enclosed_by.enclosed_by.title sube
dos niveles).
Los dos lados de una comparación pueden ser una de estas rutas, no solo un
valor fijo, que es lo que hace posible una consulta como «familias en las
que la madre y el padre comparten apellido»: father.surname == mother.surname. Encadenar y comparar se pueden combinar libremente:
father.birth.date.sortval < Date('Jan 1, 1850') avanza dos pasos desde
una familia (hasta el padre y luego hasta su evento de nacimiento) para
encontrar generaciones anteriores sin saber de antemano quiénes son.
No hay límite al número de saltos que puede dar una ruta, y cada salto
puede llegar a un tipo de registro totalmente distinto. Partiendo de la
vista Familias, father.birth.place.title == 'Chicago, Cook, Illinois, USA' va de la familia al registro Persona del padre, de ahí a su Evento
de nacimiento y de ahí al Lugar de ese evento: tres saltos por tres tipos
de registro distintos, terminando en el nombre del lugar, todo en una
línea. El mismo encadenamiento funciona desde cualquier vista, en
cualquier combinación que permitan las relaciones anteriores.
Una persona tiene exactamente un evento de nacimiento, pero cualquier
número de hijos, notas, citas u objetos multimedia asociados: eso
necesita otro tipo de comprobación. any(c.given_name == 'Steve' for c in children) coincide con una familia si alguno de los hijos cumple la
condición; omitir la condición (any(n for n in notes)) solo pregunta si
hay algo asociado, que es como not any(n for n in notes) encuentra a
las personas sin ninguna nota registrada. len(...) pregunta «cuántos»
en lugar de «al menos uno»: len([c for c in children]) > 2 encuentra
familias con más de dos hijos, y len([c for c in children if c.gender == Person.MALE]) > 1 lo restringe a contar solo los hijos varones.
Sin embargo, una colección es lo más lejos que puede llegar una consulta
en esa dirección. El encadenamiento descrito más arriba
(father.birth.place.title) solo funciona a través de relaciones que
conectan con exactamente un registro: any/len pueden decirle si algo
dentro de una colección cumple una condición, pero la consulta no puede
seguir encadenando más allá de esa coincidencia para llegar a uno de
sus propios registros relacionados. El padre de una familia tiene su
propia familia de origen, por ejemplo, pero como una persona puede
figurar como hijo de más de una familia, ese vínculo también es una
colección, un paso más de lo que una consulta puede seguir hoy. Así que
«todas las familias cuyo padre y abuelo nacieron en el mismo condado» no
es algo que GOQL pueda expresar todavía.
Todas las colecciones anteriores van hacia fuera: los propios hijos de
una familia, las propias notas de una persona. backlinks es la única
colección que va en sentido contrario: ¿hay algo más en el árbol que
apunte a este registro? Está disponible en los diez tipos de registro,
incluso en los que no tienen colecciones propias hacia fuera (una
Etiqueta no tiene hijos ni notas propias, pero muchos registros pueden
estar etiquetados, así que la condición backlinks de Tag encuentra
etiquetas que nada usa):
not any(bl for bl in backlinks) # nada hace referencia a este registro
any(bl._class == 'Person' for bl in backlinks) # al menos una Persona hace referencia a él
any(bl for bl in backlinks) and len([bl for bl in backlinks]) > 1 # referenciado por más de una cosaEsto es lo que hace posible una consulta como «todas las fuentes que ya
nadie cita» o «todos los lugares sin ningún evento registrado en ellos»:
not any(bl for bl in backlinks), ejecutado en la vista Fuentes o
Lugares.
_class es el único campo que puede comprobar una condición
backlinks: el tipo de registro del que hace la referencia
('Person', 'Family', ...). Como quien hace la referencia en un
retroenlace puede ser cualquiera de los diez tipos de registro a la vez,
_class no se puede seguir más a fondo como una relación normal (no
existe _class.primary_name), pero sí acepta in/not in con una
lista:
any(bl._class in ['Person', 'Family'] for bl in backlinks)
any(bl._class != 'Media' for bl in backlinks)len([bl for bl in backlinks]) funciona exactamente igual que el
len(...) anterior.
Date('...') entiende texto de fecha corriente, así que
birth.date.sortval >= Date('Jan 1, 1968') encuentra a todas las
personas nacidas ese día o después. Algo que conviene saber: sortval
es siempre un único punto en el tiempo, sin ningún calificativo de
«hacia», «antes de» o «estimado»: una fecha de nacimiento introducida
como «antes de 1968» tiene el mismo sortval que un simple «Jan 1,
1968», así que una comparación >= contaría a esa persona como nacida en
la fecha límite o después, aunque «antes de» signifique lo contrario.
Cuando esa distinción importe, compare birth.date.modifier con una
constante con nombre, como Date.MOD_ABOUT.
Algunos campos, como el sexo de una persona o la confianza de una cita,
se comparan con una constante con nombre en lugar de con un número en
bruto (gender == Person.MALE o confidence >= Citation.CONF_HIGH),
tomada directamente del propio Gramps para que nunca se desincronice de
lo que Gramps realmente guarda.
GOQL es un conjunto pequeño y fijo de piezas, no un lenguaje de programación completo: todo lo que quede fuera de los patrones anteriores se rechaza con un error en lugar de intentar adivinarlo.
Esta página cubre los patrones cotidianos; el botón «i» del propio cuadro
de búsqueda, junto al campo de búsqueda de cada vista, enumera los campos
y relaciones exactos disponibles en esa vista. Para la referencia
completa de la sintaxis (cada operador, relación, colección y caso
límite, además del razonamiento detrás de cada uno), consulte
where_expr.md
en el repositorio
gramps-object-query-language,
el proyecto sobre el que se construye GOQL.
Gramps Connect is part of the family of Gramps-based software.
Using the app
- Overview
- Installing
- Deploying
- Messaging
- GOQL (advanced search)
- Gramplets & Add-on Store
- Data Model & Editing
- FAQ
Building & contributing