Survey Design
Operators & Functions
pulldata()

The pulldata() function retrieves a value from a CSV file attached to the form. Given a filename, a column to return, a column to match on, and a key value, it returns the cell at the intersection of the matching row and the result column.

pulldata('filename.csv', 'result_column', 'key_column', ${key_field})
PositionParameterDescription
1FilenameName of the CSV media file (same name used in select_one_from_file)
2Result columnThe column whose value you want to return
3Key columnThe column to match against
4Key valueThe value to match — usually a field reference like ${field}

The function returns an empty string if no match is found.


Prerequisites

The CSV file must be attached to the form as a media file. The same file referenced by pulldata() can also be used as the choice list for select_one_from_file.

Example CSV — staff.csv:

name,id,department,phone
Alice,S001,Health,+1234567890
Bob,S002,Education,+0987654321
Carol,S003,Health,+1122334455

Basic example

Look up a staff member's department and phone from their ID:

survey:

typenamelabelcalculation
select_one_from_file staff.csvstaff_idSelect staff member
calculatedeptpulldata('staff.csv', 'department', 'name', ${staff_id})
calculatephonepulldata('staff.csv', 'phone', 'name', ${staff_id})
notedept_noteDepartment: ${dept} — Phone: ${phone}

The name column in a select_one_from_file CSV is the stored value. When the enumerator selects "Alice", ${staff_id} holds "Alice", which pulldata() uses as the key to retrieve her department and phone.


Retrieving the label of a selected choice

A select_one_from_file question stores the name value. To display the human-readable label, use pulldata() to look it up:

typenamelabelcalculation
select_one_from_file villages.csvvillageSelect village
calculatevillage_labelpulldata('villages.csv', 'label', 'name', ${village})
noteconfirmYou selected: ${village_label}

Multiple lookups from one selection

You can call pulldata() multiple times on the same file to retrieve different columns for the same selected row:

typenamelabelcalculation
select_one_from_file facilities.csvfacilitySelect facility
calculatefac_typepulldata('facilities.csv', 'type', 'name', ${facility})
calculatefac_districtpulldata('facilities.csv', 'district', 'name', ${facility})
calculatefac_bedspulldata('facilities.csv', 'beds', 'name', ${facility})

Using pulldata in relevant and constraint

pulldata() can be used in relevant and constraint columns to apply logic based on looked-up values:

typenamelabelrelevantconstraint
select_one_from_file facilities.csvfacilitySelect facility
integerbed_countNumber of beds occupied. <= number(pulldata('facilities.csv', 'beds', 'name', ${facility}))

Using pulldata with once()

To evaluate pulldata() only on first load (preventing re-evaluation when the key field changes after initial entry), wrap it in once():

typenamelabelcalculation
calculateinitial_deptonce(pulldata('staff.csv', 'department', 'name', ${staff_id}))

Best Practices

  1. The key column in the CSV must match the name column used in select_one_from_file — these must be the same value.
  2. Column names in the CSV are case-sensitive — Department and department are different columns.
  3. If the key value is not found, pulldata() returns an empty string — use if(${field} != '', pulldata(...), '') to guard against empty selections.
  4. Keep CSV files small where possible — large files increase form load time on low-bandwidth connections.
  5. For data that changes between data collection rounds, update the CSV media file by uploading a new form version.

Limitations

  • pulldata() only matches the first row where the key column equals the key value — duplicate key values in the CSV are not supported.
  • The CSV file must be attached to the form before deployment; it cannot be fetched from a URL at runtime.
  • Numeric values returned by pulldata() are strings — wrap in number() when used in arithmetic: number(pulldata(...)).

rtSurvey also supports extended forms of pulldata() for reading device metadata, JWT fields, and JSON data. See App API for pulldata('app-api', ...) and the Call API page for JSON-based lookup patterns.


Extended pulldata() variants

Beyond CSV lookups, pulldata() supports several additional data sources by changing the first argument.

pulldata('app-api', key)

Read device metadata, user attributes, and app context. See the full reference on the App API page.

pulldata('app-api', 'user.name')
pulldata('app-api', 'serverTime')
pulldata('app-api', 'projectCode')

pulldata('json', jsonString, jsonpath)

Parse an inline JSON string and extract a value using a JSONPath expression. Useful when you have a JSON literal embedded in the form.

pulldata('json', '{"status":"active","code":42}', '$.code')

Returns the matched value as a string, or empty string if not found.

pulldata('jsonpath', fieldRef, jsonpath)

Extract a value from a JSON string stored in another field using a JSONPath expression. This is equivalent to substr-jsonpath(${field}, jsonpath).

pulldata('jsonpath', ${api_raw}, '$.data.id')

pulldata('jwt', tokenField, claimName)

Decode a JWT token stored in a field and return the value of a specific claim from the payload.

pulldata('jwt', ${auth_token}, 'sub')
pulldata('jwt', ${auth_token}, 'exp')

Returns empty string if the token is invalid or the claim is not present.

pulldata('instanceid')

Returns the unique instance ID of the current submission. Equivalent to the instanceID meta field.

pulldata('instanceid')

pulldata('mapping', value, mappingName)

Map a value to another using a named mapping table defined in the form configuration.

pulldata('mapping', ${district_code}, 'district_names')

Returns the mapped value, or empty string if no mapping matches.

pulldata('options', optionName)

Read a form configuration option by name.

pulldata('options', 'max_household_size')

pulldata('rawquery', path, sql, param1, ...)

Execute a SQL SELECT against a bundled SQLite .db file and return the value from the first column of the first matching row. Parameters after the SQL string are substituted in order for ? placeholders.

PositionParameterDescription
1'rawquery'Literal string identifying this variant
2pathFile path in concat(${family_path}, '/file.db::tableName') format
3SQLA SELECT statement using ? as positional placeholders
4+paramsValues substituted for each ? in order — usually field references like ${field}

Returns an empty string if no row matches.

Example — look up a province name by ID:

pulldata('rawquery',
  concat(${family_path}, '/locations.db::provinces'),
  'SELECT name FROM provinces WHERE id = ?',
  ${province_id})

Example — look up a ward name filtered by both province and district codes:

pulldata('rawquery',
  concat(${family_path}, '/locations.db::wards'),
  'SELECT name FROM wards WHERE province_code = ? AND district_code = ?',
  ${province_code},
  ${district_code})

Unlike the standard four-argument pulldata() which matches a single key column in a CSV file, the rawquery variant executes a full SQL SELECT against a SQLite database, allowing multi-column WHERE conditions and any column as the return value.

rawquery is commonly used with autocomplete fields for hierarchical location lookups. See Local Database Search for details on building .db files and wiring them to pulldata('rawquery', ...).