@UVUNIQUE
@UVUNIQUE is a REDCap action tag that checks a value against every other record as it is typed, with project, DAG or event scope and optional composite keys. REDCap has no native field-level uniqueness.
REDCap has no native field-level uniqueness. @UVUNIQUE checks the value
against every other record as it is typed — a CSRF-protected module
AJAX call, no page reload — with the usual message / confirm / block enforcement.
Syntax
@UVUNIQUE unique across the project
@UVUNIQUE=event scope: project | dag | event
@UVUNIQUE={"with":["site"],
"message":"Specimen already registered",
"blockSave":"hard"}
@UVUNIQUE={"also":["typed_id"]} also look in another field
Scopes and composite keys
project(the default) — unique across the whole project.dag— unique within each Data Access Group.event— unique within the same event of a longitudinal project.withmakes the key composite: the value plus those fields together must be unique, such as a specimen ID within its site.alsolists up to 5 more fields to look for the value in. On a scannedscan_id,{"also":["typed_id"]}refuses an ID that another record holds inscan_idor intyped_id. The search runs one way, so tagtyped_idwith{"also":["scan_id"]}as well to stop a typed ID that was scanned earlier. The record being saved is never compared with itself; use@UVASSERTto keep two fields of one record apart. Each field must store the same kind of value as the tagged field, andalsocannot be combined with"scope":"record". A placement that could never match is refused, such as analsofield and awithfield on two different repeating instruments.
when decides whether this record's value is checked. Other records are
searched whatever their own when says, on the form, in the post-save audit
and in the Validation scan.
Under dag scope, records in no group form one group of their
own. They are compared against each other, not exempted. "No DAG" is a scope
like any other, and the alternative reading — that an ungrouped record has nothing to
be compared with — would let the rule lapse exactly where records are hardest to
attribute. Use project scope if you want them compared against
everything.
Privacy posture
The endpoint answers only for fields that carry a unique rule, so it cannot be used
to probe arbitrary fields for the existence of a value. Staff see the colliding record
id, and the also field that holds the value, only when the record is inside
their own Data Access Group.
What counts as the same value
Stored values, trimmed, with A-Z letter case ignored: SP-1 and
sp-1 are duplicates. Add "caseSensitive":true when case tells two
values apart. In a field that holds numbers (an integer or number Text field, or a slider)
values compare by value, so 007 and 7 are duplicates. On a plain
Text field they stay text. @UVEXISTS compares the same way. A saved Missing
Data Code is never a duplicate: ten records marked UNK share no value.
Up to 2.1.0-rc.2 the comparison was exact. A project that already holds both spellings of a value gets duplicate findings after the upgrade.
Surveys: opt-in, and never on an identifier
Survey respondents are not logged in, so an "already used" answer tells anyone
holding the survey link that a specific value is in the study — one value at a time.
{"surveys":true} is therefore:
- Off by default.
- Answered as a bare yes/no, never a record id.
- Rate-limited. A value the filtered read does not find is confirmed by a read of the
whole field, which a survey makes only within a read budget it shares with
@UVEXISTS(60 a minute per project). Past it the answer is "could not check", which does not block, except that an "already used" the page held before Save asked again still stands. - Refused outright on any field REDCap flags as an Identifier —
there it would let a stranger test whether a named person is enrolled, so the module
makes that a configuration error rather than trusting a warning to be read. The same
holds for a
withoralsofield. - With
also, limited to fields on the tagged field's own instrument, so a respondent is only told about fields of the survey they are filling in.
A reasonable use is a non-identifying response token, to stop the same person submitting twice. Leaving it off costs no data quality: survey submissions are still covered by the post-save audit and the Validation scan.
The race is audited, not denied
Two near-simultaneous saves can both pass the live check. The post-save audit
re-checks the saved value against every other record and logs a collision as
type: unique, reason: duplicate-value — review the module log
for races. A failed check fails open, so a network error on a first check
never traps a save. When Save asks again about an "already used" the page has held for
30 seconds or more and gets no answer, that earlier answer stands and is enforced.
Field types
Text, Notes, dropdown, radio, yes/no, true/false and slider. Composes with the other modes on the same field.