--- title: "Pagination and nested data" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Pagination and nested data} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ```{r setup} library(obrasgovr) ``` ## Retrieve one page first Paginated functions retrieve one page by default. This prevents an overly broad query from triggering thousands of requests unintentionally. ```{r one-page, eval = FALSE} projects <- get_projects( uf_principal = "PE", page = 1, page_size = 200 ) result_metadata(projects) ``` `page` selects the first page, and `page_size` controls how many records the API can return per page. The supported page size is between 1 and 200. ## Collect a controlled number of pages Set `all_pages = TRUE` to combine successive pages into one tibble. During exploration, also set a finite `page_limit` so the maximum number of requests is visible in the code. ```{r limited-pages, eval = FALSE} projects_sample <- get_projects( uf_principal = "PE", all_pages = TRUE, page_limit = 3, page_size = 200 ) result_metadata(projects_sample)$pages_retrieved ``` Collection starts at `page`. Therefore, `page = 4` and `page_limit = 3` retrieve at most pages 4, 5, and 6. ```{r page-window, eval = FALSE} projects_window <- get_projects( uf_principal = "PE", page = 4, all_pages = TRUE, page_limit = 3, page_size = 200 ) ``` Use `page_limit = Inf` only when the complete result is required. Requests are performed sequentially, and the package's retry and throttling policies remain active. ## Understand nested relationships A project may have multiple executors, recipients, transferors, policy areas, funding sources, and geometries. These relationships are preserved as list-columns instead of being reduced to the first item. The following API-shaped example is created locally so its transformations are executed when the vignette is built: ```{r nested-sample} projects <- tibble::tibble( id_projeto_investimento = c("100.00-01", "200.00-02"), desc_nome = c("School renovation", "Health unit construction"), executores = list( list( list(nome_organizacao = "Municipality A", cnpj = "00000000000100"), list(nome_organizacao = "State Agency", cnpj = "00000000000200") ), list( list(nome_organizacao = "Municipality B", cnpj = "00000000000300") ) ) ) projects ``` Inspect one cell without changing the project table: ```{r inspect-one-cell} projects$executores[[1]] ``` ## Normalize one nested relationship Use `tidyr::unnest_longer()` to create one row per executor and `tidyr::unnest_wider()` to turn executor fields into columns. ```{r normalize-executors} executors <- projects |> dplyr::select(id_projeto_investimento, executores) |> tidyr::unnest_longer(executores) |> tidyr::unnest_wider(executores) executors ``` Keeping normalization explicit avoids multiplying unrelated nested relationships. If executors and funding sources were unnested together, every executor could be paired with every funding source for the same project. ## Work across collected pages Pages are combined before the tibble is returned, so ordinary tidyverse code does not need to know which page contained a record. ```{r summarize, eval = FALSE} projects_sample |> dplyr::count(situacao, sort = TRUE) ``` ## Save data with retrieval context For reproducible work, store the query, pagination metadata, and API update timestamp with the data. ```{r reproducibility, eval = FALSE} query <- list( uf_principal = "PE", all_pages = TRUE, page_limit = 3, page_size = 200 ) provenance <- list( query = query, pagination = result_metadata(projects_sample), source_updated_at = get_last_update() ) saveRDS( list(data = projects_sample, provenance = provenance), "projects-pe.rds" ) ``` This bundle records what was requested, how much was retrieved, when the request ran, and when ObrasGov last updated its source data.