Common Recipes
Practical, copy-and-adapt examples for real surveys. Every expression uses realistic variable names — replace them with your survey's question names.
For the exact behaviour of each function, see the Expression Reference and Date and Time Reference.
Age
Question: dob (date) · Calculated question: age
age(${dob}, ${interview_date})where interview_date is an ordinary date question you create in the
survey ("Interview date"). MQUAD does not invent an interview date — the
calculation needs two explicitly supplied dates.
Alternatively, use today's date:
age(${dob}, today())The difference: ${interview_date} is fixed once answered; today() is
re-evaluated each time the calculation runs, so the age creeps up to the next
birthday on the day itself.
Child age in months
age-months(${dob}, ${visit_date})For a child under two, months are more meaningful than years.
Pregnancy week
Questions: lmp (date) · visit_date (date)
gestational-weeks(${lmp}, ${visit_date})Pregnancy week + remaining days
Two calculated fields, usually shown together as "16 weeks + 4 days":
gestational-weeks(${lmp}, ${visit_date})gestational-days(${lmp}, ${visit_date})gestational-days returns the 0–6 remainder, and
gestational-total-days(${lmp}, ${visit_date}) returns the raw total.
BMI
Questions: weight_kg (decimal) · height_cm (decimal)
bmi(${weight_kg}, ${height_cm})Height is in centimetres. bmi(70, 175) ≈ 22.86. Do not pass metres.
Days between visits
date-diff('days', ${visit_1}, ${visit_2})This is signed: reversing the arguments negates the result. Prefer it over
the legacy days-between, whose argument order differs by platform.
Months since enrollment
date-diff('months', ${enrollment_date}, ${visit_date})Completed months — a visit exactly 30 days after enrollment is still 0
months.
Follow-up date
date-add(${visit_date}, 14, 'days')Adds 14 calendar days. Month-end clamping applies to 'months'/'years'
units: date-add('2026-01-31', 1, 'months') → 2026-02-28.
Estimated due date
A generic date calculation (presented as a calculation, not medical advice):
date-add(${lmp}, 280, 'days')Interview duration
Using the legacy duration (end first!):
duration(${end_time}, ${start_time}, 'minutes')or with the newer time-diff:
time-diff('minutes', ${start_time}, ${end_time})time-diff treats both plain times as clock values with no midnight rollover
(23:00 → 01:00 is -22 hours). For durations that cross midnight, use
datetime questions instead.
Show "Other, specify"
Skip logic on the "Other, specify" question, shown when Other is selected in a select-multiple:
selected(${symptoms}, 'other')For a select-one the simpler equality works:
${symptoms} = 'other'Minimum number of selections
Validation on a select-multiple question:
count-selected(${symptoms}) >= 2Age-based section
Skip logic on the first adult question (age is a calculated question):
${age} >= 18Pregnancy section
Skip logic on the first pregnancy question:
${pregnant} = 'yes'Child eligibility
Show child-specific questions when the respondent is pregnant and under a certain age (combines a calculated value and an answer):
${pregnant} = 'yes' and ${age} < 18Copy household identifier
Default value on a text question:
#household_numGenerate compound identifier
Calculation on a text question (functions available):
concat(${state}, '-', ${district}, '-', ${household_num})produces e.g. MH-PUNE-0012. (In a default value the same composition uses
#state-#district-#household_num — no functions there.)
Conditional calculated value
if(${age} >= 18, 'adult', 'child')Date validation
End date cannot be earlier than start date — validation on end_date:
${end_date} >= ${start_date}Numeric range validation
Weight must be between realistic bounds — validation on weight_kg:
. >= 2 and . <= 200The dot . is the current question's value.
Required only under a condition
MQUAD's required flag is unconditional. To make a field required only when a
condition holds, use if() as a validation:
if(${has_children} = 'yes', . != '', .)Advanced examples
Multiple conditions
Show a question when the respondent is female, aged 15–49, and married:
${sex} = 'female' and ${age} >= 15 and ${age} <= 49 and ${marital_status} = 'married'Read: "female AND age 15 to 49 AND married".
Multiple-choice logic
Show treatment-details questions when any relevant treatment was selected:
selected(${treatments}, 'antibiotics') or selected(${treatments}, 'hospital') or count-selected(${treatments}) > 0Since any selection means at least one, the simpler form works too:
count-selected(${treatments}) >= 1Chained calculated values
A dependency chain — DOB → Age → Age group → section visibility:
dob(date question, answered by the respondent)age(calculated):age(${dob}, ${interview_date})age_group(calculated):if(${age} < 5, 'under5', if(${age} < 18, 'child', 'adult'))- Section skip logic:
${age_group} = 'adult'
When dob changes, MQUAD's dependency graph re-evaluates age, then
age_group, then the section visibility — in that order.
BMI chain
weight_kgandheight_cm(answered)bmi(calculated):bmi(${weight_kg}, ${height_cm})bmi_category(calculated):
if(${bmi} < 18.5, 'underweight', if(${bmi} < 25, 'normal', if(${bmi} < 30, 'overweight', 'obese')))if() nests: the second if runs only when the first condition is false.
Pregnancy chain
lmp(answered)gest_age_weeks(calculated):gestational-weeks(${lmp}, ${visit_date})trimester(calculated):
if(${gest_age_weeks} < 13, 'first', if(${gest_age_weeks} < 28, 'second', 'third'))- Follow-up questions with skip logic like
${trimester} = 'third'
There is no dedicated trimester function — conditional expressions derive it, as shown.
Conditional calculated value with numbers
if(${member_status} = 'premium', ${total} * 0.2, 0)20% discount for premium members, else 0.
