Разширени повторения
Разширени модели за групи за повторение: динамични броячи, вложени повторения, обобщаване на данни от повторения и препратка към стойности в рамките на повторения.
This page covers advanced patterns for working with repeat groups in rtSurvey. For the basics of setting up a repeat group, see Grouping and Repeats.
Dynamic repeat count
By default, the enumerator decides how many times to repeat. You can fix the number of repetitions using repeat_count:
| type | name | label | repeat_count |
|---|---|---|---|
| begin_repeat | household_members | Household member | ${num_members} |
| text | member_name | Member name | |
| integer | member_age | Age | |
| end_repeat |
The repeat runs exactly ${num_members} times, where num_members was collected earlier in the form. The enumerator cannot add or remove instances.
Indexed access: indexed-repeat()
Access a specific repeat instance’s field value from outside the repeat group using indexed-repeat(repeatedField, repeatGroup, index):
| type | name | label | calculation |
|---|---|---|---|
| calculate | first_name | indexed-repeat(${member_name}, ${household_members}, 1) | |
| calculate | second_name | indexed-repeat(${member_name}, ${household_members}, 2) |
This is useful for building summary fields or referencing the “primary” member’s data after the repeat.
Current instance position: index()
Inside a repeat group, index() returns the 1-based position of the current instance. Use it to label each repetition or create unique identifiers:
| type | name | label |
|---|---|---|
| begin_repeat | plots | Plot |
| note | plot_label | Plot number ${index()} |
| text | plot_id | Plot ID |
| end_repeat |
Referencing fields in the same instance
Within a repeat, use ${fieldname} to reference another field in the same repeat instance. There is no need for indexed-repeat() within the same loop:
| type | name | label | relevant |
|---|---|---|---|
| begin_repeat | members | Member | |
| text | member_name | Name | |
| integer | member_age | Age | |
| text | school_name | School name | ${member_age} < 18 |
| end_repeat |
Referencing parent fields from inside a repeat
Fields outside (above) the repeat group can be referenced normally with ${fieldname}:
| type | name | label |
|---|---|---|
| text | village | Village name |
| begin_repeat | plots | Agricultural plot |
| note | plot_context | Plots in ${village} |
| end_repeat |
Summarising repeat data
Use repeat aggregate functions outside the repeat group to summarise:
| Function | Example | Description |
|---|---|---|
count(group) | count(${household_members}) | Number of instances |
sum(field) | sum(${loan_amount}) | Sum of a numeric field |
min(field) | min(${member_age}) | Minimum value |
max(field) | max(${member_age}) | Maximum value |
join(sep, field) | join(', ', ${member_name}) | Comma-separated list |
count-if(group, expr) | count-if(${members}, ${member_age} < 18) | Conditional count |
sum-if(field, expr) | sum-if(${loan_amount}, ${loan_amount} > 500) | Conditional sum |
join-if(sep, field, expr) | join-if(', ', ${name}, ${age} >= 18) | Conditional join |
Пример: Household summary
| type | name | label | calculation |
|---|---|---|---|
| integer | num_members | How many members? | |
| begin_repeat | members | Member | ${num_members} |
| text | member_name | Name | |
| integer | member_age | Age | |
| end_repeat | |||
| calculate | total_members | count(${members}) | |
| calculate | children_count | count-if(${members}, ${member_age} < 18) | |
| calculate | adult_names | join-if(', ', ${member_name}, ${member_age} >= 18) | |
| note | summary | ${total_members} members; ${children_count} under 18. Adults: ${adult_names} |
Nested repeats
A repeat group can contain another repeat group. Use this carefully — nested repeats add complexity and can be confusing for enumerators.
| type | name | label |
|---|---|---|
| begin_repeat | households | Household |
| text | hh_id | Household ID |
| begin_repeat | hh_members | Member |
| text | member_name | Member name |
| end_repeat | ||
| end_repeat |
To reference a field in an outer repeat from the inner repeat, use ${fieldname} — it resolves to the nearest matching ancestor:
Inside the hh_members repeat, ${hh_id} returns the ID of the current household, not all households.
Rank inside repeat groups: rank-index()
When a rank field exists inside a repeat, use rank-index(instanceNumber, repeatedField) from outside to get the ordinal rank of a specific instance:
| type | name | label | calculation |
|---|---|---|---|
| calculate | top_scorer | rank-index(1, ${score}) |
rank-index(1, ${score}) returns the instance index of the highest score.
Best Practices
- Always use
repeat_countwhen the number of repetitions is known in advance — it prevents enumerators from accidentally adding or removing instances. - Keep repeat groups focused — a repeat with 20+ questions per instance is difficult to navigate.
- Name repeat groups clearly (e.g.,
household_members, notrepeat1) — the name appears in function calls and exported data. - Test with the maximum expected number of instances to verify performance.
- Use
field-listappearance on the repeat group to show all fields on one screen per instance (mobile).
Limitations
indexed-repeat()requires a valid index (1 to count of instances) — out-of-range indices return empty.- Nested repeats beyond 2 levels are not recommended and may cause display issues on some clients.
- Aggregate functions (
sum,count, etc.) operate on the entire repeat group — you cannot aggregate a subset of instances without*-ifvariants.