Skip to contents

Introduction

We can find records using the family of get_*() functions. Most of these are about finding familial relations to an individual.

We illustrate their functionality using the family below consisting of three generations: A pair of parents who has a single child (named ‘Main Person’). This person forms two separate family groups with two spouses, each resulting in two children.

library(gedcomS7)

main_person <- IndividualRecord(pers_names = "Main Person", sex = "M")

three_gen <- new_gedcom() |> 
  push_record(main_person) |> 
  add_parents("@I1@", fath_name = "Parent 1", moth_name = "Parent 2") |> 
  add_spouse("@I1@", spou_name = "Spouse 1") |> 
  add_spouse("@I1@", spou_name = "Spouse 2") |> 
  add_children("@F2@", sexes = "MM", chil_names = c("Son 1", "Son 2")) |> 
  add_children("@F3@", sexes = "FF", chil_names = c("Daughter 1", "Daughter 2")) 
#> New Individual record added with xref @I1@
#> New Family record added with xref @F1@
#> New Individual record added with xref @I2@
#> New Individual record added with xref @I3@
#> New Individual record added with xref @I4@
#> New Family record added with xref @F2@
#> New Individual record added with xref @I5@
#> New Family record added with xref @F3@
#> New Individual record added with xref @I6@
#> New Individual record added with xref @I7@
#> New Individual record added with xref @I8@
#> New Individual record added with xref @I9@

Image courtesy of Topola Genealogy Viewer (a great tool for visualising GEDCOM files!)

Immediate relations

The examples below illustrate the functions. All the functions return xrefs, so a helper function is created to convert xrefs for Individual records into the people’s names.

main_person <- "@I1@"

# Helper to convert xrefs to names
xref_to_name <- \(x) unlist(lapply(x, \(xref) pull_record(three_gen, xref)@PRIMARY_NAME))

get_indi_partners(three_gen, main_person) |> xref_to_name()
#> [1] "Spouse 1" "Spouse 2"

get_indi_parents(three_gen, main_person) |> xref_to_name()
#> [1] "Parent 1" "Parent 2"

get_indi_children(three_gen, main_person) |> xref_to_name()
#> [1] "Son 1"      "Son 2"      "Daughter 1" "Daughter 2"

get_indi_siblings(three_gen, "@I6@") |> xref_to_name()
#> [1] "Son 2"

get_indi_siblings(three_gen, "@I6@", inc_half = TRUE) |> xref_to_name()
#> [1] "Son 2"      "Daughter 1" "Daughter 2"

get_fam_as_child(three_gen, main_person)
#> [1] "@F1@"

get_fam_as_spouse(three_gen, main_person)
#> [1] "@F2@" "@F3@"

get_fam_partners(three_gen, "@F1@")
#> [1] "@I2@" "@I3@"

get_fam_children(three_gen, "@F2@")
#> [1] "@I6@" "@I7@"

Many functions include a pedigrees parameter which allows you to specify the types of relationships allowed (all are allowed by default, specify “BIRTH” if you only want biological). Allowed values for pedigrees are below.

unname(val_pedigree_types())
#> [1] "BIRTH"   "ADOPTED" "FOSTER"  "SEALING" "OTHER"

If we add an adopted child to family “@F3@” we can see the difference this parameter makes:

adopted_child <- IndividualRecord(
  pers_names = "Adopted child",
  fam_links_chil = FamilyLinkChild(fam_xref = "@F3@", pedigree = "ADOPTED")
)

three_gen <- push_record(three_gen, adopted_child)
#> New Individual record added with xref @I10@

get_fam_children(three_gen, "@F3@") |> xref_to_name()
#> [1] "Daughter 1"    "Daughter 2"    "Adopted child"
get_fam_children(three_gen, "@F3@", pedigrees = "BIRTH") |> xref_to_name()
#> [1] "Daughter 1" "Daughter 2"
get_fam_children(three_gen, "@F3@", pedigrees = "ADOPTED") |> xref_to_name()
#> [1] "Adopted child"

Distant relations

One of the more sophisticated features of gedcomS7 is the ability to manipulate entire branches of your tree.

We can use the get_descendants() function to identify the descendants of Main Person. By default it will exclude the individual, all spouses, and all associated family records:

get_descendants(three_gen, "@I2@") # Parent 1
#> [1] "@I1@"  "@I6@"  "@I7@"  "@I8@"  "@I9@"  "@I10@"

Setting inc_part = TRUE will include all partners and their descendants, and all descendants’ partners:

get_descendants(three_gen, "@I2@", inc_part = TRUE)
#> [1] "@I3@"  "@I4@"  "@I5@"  "@I1@"  "@I6@"  "@I7@"  "@I8@"  "@I9@"  "@I10@"

Setting inc_indi = TRUE will include the individual:

get_descendants(three_gen, "@I2@", inc_indi = TRUE)
#> [1] "@I2@"  "@I1@"  "@I6@"  "@I7@"  "@I8@"  "@I9@"  "@I10@"

Setting inc_fam = TRUE will include the individual’s families where they are a spouse/child, and all descendants’ families:

get_descendants(three_gen, "@I2@", inc_fam = TRUE)
#> [1] "@F1@"  "@F2@"  "@F3@"  "@I1@"  "@I6@"  "@I7@"  "@I8@"  "@I9@"  "@I10@"

We can deal with ancestors in a similar way using the get_ancestors() function. There is also a get_indi_cousins() function which allows you to find all types of cousin for an individual.

Supporting records

Whilst the functions above focus on Individual and Family records, the get_supporting_recs() function identifies all other types of records referenced by a set of records.

For example, below we create three different types of supporting record; media, repository, and source. The source record is linked to both the media and repository record.

We then add a link to the source record in the record of Main Person.

supporting_media <- MediaRecord(
  files = MediaFile("myfile.mp3", media_type = "audio/mp3")
  )
supporting_repo <- RepositoryRecord(repo_name = "Library")
# Source record is itself linked to the Media and Repository records
supporting_sour <- SourceRecord(
  media_links = three_gen@records@XREFS_NEXT["OBJE"],
  repo_citations = three_gen@records@XREFS_NEXT["REPO"]
)

three_gen <- three_gen |> 
  push_record(supporting_media) |> 
  push_record(supporting_repo) |> 
  push_record(supporting_sour)
#> New Multimedia record added with xref @M1@
#> New Repository record added with xref @R1@
#> New Source record added with xref @S1@

# Pull Main Person so we can add a link to the new source record
main_person <- pull_record(three_gen, "@I1@")
main_person@citations <- "@S1@"
three_gen <- push_record(three_gen, main_person)

Now, when we get the supporting records, it not only retrieves the record directly referenced in Main Person’s record, but also recognises the downstream dependencies of the repository and media records.

get_supporting_recs(three_gen, "@I1@")
#> [1] "@S1@" "@R1@" "@M1@"

Pattern matching

Finally, the get_records_by_pattern() function retrieves all records where a value matches a given regular expression (case insensitive).

get_records_by_pattern(three_gen, "library")
#> [1] "@R1@"
get_records_by_pattern(three_gen, "son")
#> [1] "@I1@" "@I6@" "@I7@"

By default, this returns the xrefs only. If you want to see why the records were matched, set return_context = TRUE and it will return all the lines where a match occurred:

get_records_by_pattern(three_gen, "son", return_context = TRUE)
#> $`@I1@`
#> [1] "1 NAME Main Person"
#> 
#> $`@I6@`
#> [1] "1 NAME Son 1"
#> 
#> $`@I7@`
#> [1] "1 NAME Son 2"

You can then refine your pattern to include word boundaries etc.

get_records_by_pattern(three_gen, "\\bson\\b", return_context = TRUE)
#> $`@I6@`
#> [1] "1 NAME Son 1"
#> 
#> $`@I7@`
#> [1] "1 NAME Son 2"