Skip to content

GOQL.nl

Doug Blank edited this page Oct 11, 2026 · 1 revision

🌐 English · Deutsch · Español · Français · 简体中文

GOQL

Elke lijstweergave in Gramps Connect — Personen, Gezinnen, Gebeurtenissen enzovoort — heeft een zoekvak. Standaard doet typen daarin een snelle overeenkomst op gewone tekst met een handvol veelgebruikte velden van die weergave (voor Personen: Gramps-ID en naam; voor Plaats: ID, titel en plaatsnaam; enzovoort) — genoeg voor de meeste alledaagse zoekopdrachten, en de standaard omdat het eenvoudiger is dan een zoektaal.

Naast het vak staat een vinkje: "Gramps Object Query Language gebruiken." Zet het aan, en hetzelfde vak accepteert in plaats daarvan een volledige GOQL-voorwaarde (gramps-object-query-language) — een kleine taal, speciaal gebouwd om Gramps-records te doorzoeken, die dingen kan waar het zoeken op gewone tekst helemaal niet bij komt: over relaties heen reiken (een join, in databasetermen — "elk gezin waarvan moeder en vader dezelfde achternaam hebben"), en ze zelfs achterwaarts volgen ("elke notitie waar niets meer naar verwijst"). Deze pagina is voor iedereen die zo'n voorwaarde wil schrijven — geen programmeerervaring nodig.

GOQL drijft ook de aanroepen filter()/db.get_number_of() van Gramplets aan en het argument where= van people()/ families()/enz. — dezelfde syntaxis die u met het vinkje aan in het zoekvak zou typen, werkt ook vanuit de Python-code van een add-on. (db.get_number_of()/het oudere kale count() zijn functies van de Gramplet-API om overeenkomende records te tellen, niet de eigen any/len van GOQL die hieronder worden behandeld — iets anders, dezelfde naam.)

Wilt u het helemaal niet met de hand schrijven? De knop "Filters" naast de titel van elke lijst biedt tientallen veelgebruikte regels als gewone vinkjes — combineerbaar met AND/OR, nestbaar en om te keren — en bouwt daaronder precies dezelfde GOQL, alleen-lezen getoond zodat u kunt zien wat er is geschreven. Zie daarvoor de lijst met functies op de pagina Overzicht. "+ Nieuwe aangepaste regel…" is de enige plek in dat dialoogvenster die nog een ruwe GOQL-voorwaarde met de hand accepteert, met dezelfde syntaxis als deze hele pagina — zodra die is opgeslagen en een naam heeft, wordt ze vanaf dat moment als gewoon vinkje hergebruikt, en nooit opnieuw getypt.

Het basisidee

Een query wordt altijd geschreven in de context van een weergave — Persoon, Gezin, Gebeurtenis enzovoort — en is slechts één voorwaarde:

surname == 'Smith'

Dit leest als: zoek in de weergave Persoon de records waarvan de achternaam gelijk is aan 'Smith'. De weergave waarin u zoekt, bepaalt op welk soort record de voorwaarde van toepassing is.

Een paar symbolen komen steeds terug:

Symbool Betekent
==, != is gelijk aan / is niet gelijk aan
<, <=, >, >= is kleiner dan, ten hoogste, groter dan, ten minste (eerder/later, kleiner/groter)
and, or, not voorwaarden combineren, of er een omkeren
in [ ... ] komt overeen met een van de waarden in een lijst
'text' in field komt overeen als field ergens 'text' bevat
like(field, 'pattern') komt overeen met een tekstpatroon, waarin % staat voor "wat dan ook"
regex(field, 'pattern') komt overeen met een reguliere expressie, voor wie die al kent

Tekstwaarden staan tussen enkele aanhalingstekens ('Smith'); getallen niet (1968).

Voorwaarden combineren

and vereist dat beide kanten waar zijn; or heeft er maar één nodig. Beide lezen natuurlijk: gender == Person.MALE and surname == 'Smith' vindt elke man met de naam Smith, terwijl given_name == 'John' or surname == 'Doyle' iedereen met de voornaam John vindt of wie dan ook met de achternaam Doyle. De twee mengen werkt net als gewone rekenkunde, waar vermenigvuldigen vóór optellen gaat — and wordt vóór or gecontroleerd — maar haakjes maken de bedoeling hoe dan ook duidelijk: (gender == Person.MALE and surname == 'Smith') or given_name == 'Mary' vindt elke mannelijke Smith, plus iedereen die Mary heet, van welk geslacht dan ook.

not keert een voorwaarde om en komt overeen wanneer wat erin staat niet waar is: not (surname == 'Smith') is iedereen wiens achternaam niet Smith is. Vergelijkingen kunnen ook worden geketend, zoals echt Python toestaat — Date('Jan 1, 1900') < birth.date.sortval < Date('Jan 1, 1950') vindt iedereen die strikt tussen die twee datums is geboren, op één regel in plaats van twee die met and zijn verbonden.

Tekst laten overeenkomen

Naast een gewone == dekken een paar lossere manieren om tekst te laten overeenkomen de meeste alledaagse zoekopdrachten. given_name in ['John', 'Jane'] komt overeen met elke naam in de lijst — voeg er zoveel toe als u wilt. 'an' in given_name komt overal in de naam overeen (Jane, Alexander, Susan, ...) zonder jokertekens. like(field, 'J%') komt overeen met een patroon waarin % staat voor "wat dan ook", dus like(given_name, 'J%') komt overeen met John, Jane, James enzovoort. Voor wie al vertrouwd is met reguliere expressies is regex(field, 'pattern') nog krachtiger — regex(surname, '^[SD]') vindt in één keer elke Smith en Doyle, iets wat like(...) niet kan uitdrukken zonder voor elke beginletter een aparte voorwaarde te schrijven.

Gerelateerde records bereiken

Een veld hoeft niet direct op het record te staan waarin u zoekt. birth en death reiken van een persoon naar diens geboorte- of overlijdensgebeurtenis, dus birth.date.sortval is de datum van die gebeurtenis, en birth.place.title volgt die nog een stap verder, naar de plaats van die gebeurtenis. Hetzelfde idee werkt bij andere recordtypen: father en mother reiken van een gezin naar het eigen Persoon-record van elke ouder (father.surname == 'Smith'), source reikt van een citaat naar wat het citeert, en enclosed_by reikt van een plaats naar de plaats die haar omvat (bijvoorbeeld de provincie van een stad — en het is met zichzelf te ketenen, dus enclosed_by.enclosed_by.title reikt twee niveaus omhoog).

Beide kanten van een vergelijking kunnen zo'n pad zijn, niet alleen een vaste waarde, en dat maakt een query als "gezinnen waarin moeder en vader dezelfde achternaam hebben" mogelijk: father.surname == mother.surname. Ketenen en vergelijken zijn vrij te combineren — father.birth.date.sortval < Date('Jan 1, 1850') reikt twee stappen vanaf een gezin (naar de vader, en dan naar zijn geboortegebeurtenis) om oudere generaties te vinden zonder van tevoren te weten wie dat zijn.

Er is geen limiet aan het aantal van zulke sprongen dat één pad kan maken, en elke sprong kan op een heel ander soort record landen. Vanuit de weergave Gezin reikt father.birth.place.title == 'Chicago, Cook, Illinois, USA' van het gezin naar het eigen Persoon-record van de vader, van daar naar zijn geboortegebeurtenis, en van daar naar de Plaats van die gebeurtenis — drie sprongen door drie verschillende soorten records, eindigend bij de naam van de plaats, allemaal op één regel. Hetzelfde ketenen werkt vanuit elke weergave, in elke combinatie die de relaties hierboven toestaan.

Verzamelingen: any en len

Een persoon heeft precies één geboortegebeurtenis, maar een willekeurig aantal kinderen, notities, citaten of gekoppelde media — die vragen om een ander soort controle. any(c.given_name == 'Steve' for c in children) komt overeen met een gezin als een kind aan de voorwaarde voldoet; de voorwaarde weglaten (any(n for n in notes)) vraagt alleen of er überhaupt iets is gekoppeld, en zo vindt not any(n for n in notes) personen zonder vastgelegde notities. len(...) vraagt "hoeveel" in plaats van "ten minste één" — len([c for c in children]) > 2 vindt gezinnen met meer dan twee kinderen, en len([c for c in children if c.gender == Person.MALE]) > 1 beperkt dat tot het tellen van alleen de zonen.

Een verzameling is wel zo ver als één query in die richting kan reiken. Het hierboven beschreven ketenen (father.birth.place.title) werkt alleen via relaties die met precies één record verbonden zijn — any/len kunnen u vertellen of iets binnen een verzameling aan een voorwaarde voldoet, maar de query kan daarna niet verder ketenen voorbij die overeenkomst om een van diens eigen gerelateerde records te bereiken. De vader van een gezin heeft bijvoorbeeld zijn eigen oudergezin — maar omdat een persoon als kind van meer dan één gezin kan zijn vastgelegd, is die koppeling ook een verzameling, één stap verder dan een query momenteel kan volgen. Dus "elk gezin waarvan vader en grootvader in dezelfde provincie zijn geboren" kan GOQL nog niet uitdrukken.

Omgekeerde verwijzingen: backlinks

Elke verzameling hierboven reikt naar buiten — de eigen kinderen van een gezin, de eigen notities van een persoon. backlinks is de enige verzameling die de andere kant op reikt: verwijst er iets anders in de stamboom naar dit record? Die is beschikbaar vanuit elk van de tien recordtypen, zelfs vanuit typen zonder eigen uitgaande verzamelingen (een Label heeft geen eigen kinderen of notities, maar veel records kunnen een label krijgen, dus de eigen backlinks-voorwaarde van Tag vindt labels die nergens worden gebruikt):

not any(bl for bl in backlinks)                                    # niets verwijst naar dit record
any(bl._class == 'Person' for bl in backlinks)                     # ten minste één Persoon verwijst ernaar
any(bl for bl in backlinks) and len([bl for bl in backlinks]) > 1  # meer dan één ding verwijst ernaar

Dat maakt een query als "elke bron die niemand meer citeert" of "elke plaats zonder vastgelegde gebeurtenissen" mogelijk — not any(bl for bl in backlinks), uitgevoerd in de weergave Bron of Plaats.

_class is het enige veld dat een backlinks-voorwaarde kan testen — het eigen recordtype van de verwijzer ('Person', 'Family', ...). Omdat de verwijzer van een backlink tegelijk elk van de tien recordtypen kan zijn, kan _class niet dieper worden gevolgd zoals een normale relatie — er is geen _class.primary_name — maar het accepteert wel in/not in met een lijst:

any(bl._class in ['Person', 'Family'] for bl in backlinks)
any(bl._class != 'Media' for bl in backlinks)

len([bl for bl in backlinks]) werkt precies zoals len(...) hierboven.

Datums

Date('...') begrijpt gewone datumtekst, dus birth.date.sortval >= Date('Jan 1, 1968') vindt iedereen die op of na die dag is geboren. Iets om te weten: sortval is altijd één enkel tijdstip, zonder kwalificatie als "omstreeks", "voor" of "geschat" — een geboortedatum ingevoerd als "voor 1968" heeft dezelfde sortval als gewoon "Jan 1, 1968", dus een vergelijking met >= zou die persoon als op of na de grens geboren tellen, ook al betekent "voor" precies het tegenovergestelde. Als dat onderscheid ertoe doet, vergelijk dan in plaats daarvan birth.date.modifier met een benoemde constante, zoals Date.MOD_ABOUT.

Benoemde constanten

Sommige velden, zoals het geslacht van een persoon of de betrouwbaarheid van een citaat, worden vergeleken met een benoemde constante in plaats van een ruw getal — gender == Person.MALE of confidence >= Citation.CONF_HIGH — rechtstreeks uit Gramps zelf gehaald, zodat ze nooit uit de pas lopen met wat Gramps werkelijk opslaat.

Wat GOQL niet kan

GOQL is een kleine, vaste set bouwstenen, geen volledige programmeertaal — alles buiten de patronen hierboven wordt met een foutmelding geweigerd in plaats van geraden.

Meer leren

Deze pagina behandelt de alledaagse patronen; de eigen knop "i" van het zoekvak, naast het zoekveld van elke weergave, toont de precieze velden en relaties die voor die weergave beschikbaar zijn. Voor de volledige syntaxisreferentie — elke operator, relatie, verzameling en elk randgeval, plus de redenering erachter — zie where_expr.md in de repository gramps-object-query-language, het project waarop GOQL is gebouwd.

Clone this wiki locally