Compares local data against the current table contents using a hash of specified fields, then creates/updates/deletes as needed.
Arguments
- data
A data frame representing the desired state of the table. May contain computed field columns (they are ignored).
- table
Table name or ID.
- key
Column name in
datathat uniquely identifies records (used as the merge field for upsert). Must be a single field.- base_id
Base ID (e.g.,
"appXXXXXX"). IfNULL, uses the session default set byair_set_base()or theAIRTABLE_BASE_IDenvironment variable.- hash_fields
Character vector of fields to include in the change- detection hash. If
NULL(default), all non-key, non-computed, non-attachment fields are used. Computed and attachment fields are always excluded even if explicitly listed.- delete_missing
If
TRUE(default), records in Airtable that are not indatawill be deleted.- typecast
If
TRUE(default), Airtable will attempt to coerce values.- add_fields
What to do when
datacontains columns not in the table. Passed toair_upsert(). Default is"error".- complex_fields
What to do when
datacontains list-columns with complex (nested list or data-frame) values that Airtable cannot store directly:"error"(default): abort with an informative message."warn": warn and drop those columns."json": serialize each complex value to a JSON text string and write it to asingleLineTextfield (creating the field first whenadd_fields = "yes").
- attachments
How to handle attachment fields:
"meta"(default) keeps only metadata (filename, url, size, type);"file"downloads toattachment_dir;"blob"downloads as in-memory raw vectors.- attachment_dir
Directory for downloading attachments (required when
attachments = "file"). Files are saved as{attachment_dir}/{record_id}/{filename}.- progress
Logical or
NULL. IfTRUE, shows a cli progress bar for read and upsert operations. IfNULL(default), uses optionairtable2.progress.baror env varAIRTABLE2_PROGRESS_BAR.- .token
Personal access token (resolved via
air_token()ifNULL).
Details
Computed fields (formulas, rollups, autoNumber, createdTime, lastModifiedTime, createdBy, lastModifiedBy, etc.) are automatically:
Excluded from the change-detection hash (they change server-side and would cause spurious "changed" detections on every sync)
Excluded from the upload payload (the API rejects writes to them)
Attachment fields (multipleAttachments) are always excluded from the
change-detection hash because their URLs are volatile (expire hourly).
When attachments is "file" or "blob", attachment content is uploaded
for newly created records after the sync completes.
Before hashing, both the local data and the existing Airtable records are normalized to a canonical form to prevent false-positive change detection caused by representation differences:
richTextvalues have trailing whitespace stripped (Airtable appends\n)Empty strings (
"") are converted toNAUnchecked checkbox (
FALSE) is converted toNADatevalues are formatted as"YYYY-MM-DD"stringsPOSIXctvalues are formatted as"YYYY-MM-DDTHH:MM:SS.000Z"using the value's own timezone (wall-clock), matching how Airtable round-trips themintegercolumns are coerced todoubleList-columns (multipleSelects, multipleRecordLinks, multipleCollaborators) are collapsed per-element to a
\x01-separated stringCharacter
multipleSelectsvalues (e.g."R; Python") are expanded to list form before collapsing, so they hash identically to their list counterpart
Examples
if (FALSE) { # \dontrun{
desired <- data.frame(Name = c("Alice", "Bob"), Age = c(30, 26))
result <- air_sync(desired, "Contacts", key = "Name", base_id = "appXXXXXX")
result$created
result$unchanged
} # }