MDM (Master Data Management) lets Smile CDR automatically detect when two patient records in the repository represent the same real-world person. When a match is found, MDM creates a Golden Resource — a single canonical Patient that acts as the permanent identifier for that person — and records links between the Golden Resource and each matching source record.
Golden Resource linking is one of several MDM strategies supported by Smile CDR; this tutorial demonstrates the Probabilistic MDM strategy. If you are not sure this is the right approach for your environment, start with Selecting a deduplication strategy.
This tutorial is for administrators with no prior MDM experience. It walks through every step from a fresh Smile CDR installation:
By the end you will have seen the complete MDM lifecycle for a single matched pair.
MATCH_AND_LINK mode, which requires a separately purchased MDM license. Contact sales@smiledigitalhealth.com if you need to enable this feature. An MDM module explicitly configured with MATCH_ONLY mode does not require a license — see MDM for details.
http://localhost:9100 using the default admin credentials.http://localhost:8000.MDM operations require specific permissions. Create a dedicated user rather than using the built-in admin account.
Open the User Manager
In the Web Admin Console, go to Users & Authorization → User Management and click Add User.
Set credentials and permissions
Name the user mdm-tutorial and choose a password. Grant the following permissions:
| Permission | Why it is needed |
|---|---|
FHIR_WRITE_ALL_OF_TYPE (Patient) | Create Patient resources |
FHIR_READ_ALL_OF_TYPE (Patient) | Read Patient resources and Golden Resources |
FHIR_MDM_ADMIN | Execute MDM FHIR operations such as $mdm-query-links |
MDM_ADMIN | Access MDM administrative functions |
Save the user.
MDM uses Smile CDR's subscription infrastructure to process resources in the background. Two settings must be enabled on the FHIR Storage module before any other MDM configuration will work.
Open the FHIR Storage module
In the Web Admin Console, go to Configuration → Module Config and open your FHIR Storage module.
Enable subscriptions and MDM
Locate and set the following properties:
| Property | Value |
|---|---|
| MDM Mode Enabled | true |
| Subscription Message Enabled | true |
Save and restart the module
Click Save, then restart the FHIR Storage module for the changes to take effect.
Create the module
Go to Configuration → Module Config → Add Module and choose MDM. Set the Consumer Thread Count to 1 for this tutorial.
Set the subscription dependency
Under Module Dependencies, select the default Subscription Matching module.
Enter the MDM Rule Definition Script
The MDM Rule Definition Script is a JSON document that controls how MDM finds candidates and decides whether two resources represent the same person. Paste the following JSON into the MDM Rule Definition Script field:
{
"version": "tutorial-v1",
"mdmTypes": ["Patient"],
"candidateSearchParams": [
{
"resourceType": "Patient",
"searchParams": ["birthdate"]
}
],
"candidateFilterSearchParams": [],
"matchFields": [
{
"name": "family-name",
"resourceType": "Patient",
"resourcePath": "name.family",
"matcher": {
"algorithm": "METAPHONE"
}
},
{
"name": "given-name",
"resourceType": "Patient",
"resourcePath": "name.given",
"matcher": {
"algorithm": "METAPHONE"
}
}
],
"matchResultMap": {
"family-name,given-name": "MATCH"
}
}
Here is what each section does:
mdmTypes — MDM will only process Patient resources. Other resource types are ignored.candidateSearchParams — Before running any comparisons, MDM searches the repository for existing Patients that share the same birthdate as the incoming resource. Only those candidates are passed to the next phase. Birth date is a good candidate search parameter because it is specific enough to return a small number of candidates without being so specific that typos cause candidates to be missed.matchFields — The family name and given name are compared against each candidate. METAPHONE encodes each name phonetically before comparing, so alternate spellings that sound the same — for example John and Jon — are treated as equal.matchResultMap — When both field comparisons pass, the result is MATCH. MDM automatically creates a link with no manual review required.Save and start the MDM module.
Send the following HTTP request to create the first Patient record. Replace mdm-tutorial:password with the credentials you created in Step 1.
POST http://localhost:8000/Patient
Authorization: Basic <base64(mdm-tutorial:password)>
Content-Type: application/fhir+json
{
"resourceType": "Patient",
"name": [
{
"family": "Smith",
"given": ["John"]
}
],
"birthDate": "1985-03-15",
"gender": "male"
}
The server responds with 201 Created and a Location header containing the assigned ID:
Location: http://localhost:8000/Patient/101/_history/1
Note this patient's ID — 101 in this example. Your server will assign a different value.
In the background, MDM immediately processes this resource. Because no other Patient with the same birth date exists yet, MDM creates a new Golden Resource and a link from that Golden Resource to Patient/101.
Create a second Patient. The given name is Jon rather than John. Under the Metaphone algorithm both spellings encode to the same phonetic key (JN), so this difference will not prevent a match.
POST http://localhost:8000/Patient
Authorization: Basic <base64(mdm-tutorial:password)>
Content-Type: application/fhir+json
{
"resourceType": "Patient",
"name": [
{
"family": "Smith",
"given": ["Jon"]
}
],
"birthDate": "1985-03-15",
"gender": "male"
}
Note this patient's ID as well — 102 in this example.
After a brief moment, MDM processes the second patient asynchronously:
birthdate = 1985-03-15 and finds Patient/101.SM0). Both given names encode to the same Metaphone key (JN). Both comparisons pass.MATCH link between the existing Golden Resource and Patient/102.Both source records are now linked to the same Golden Resource.
Query $mdm-query-links to see the links that were created:
GET http://localhost:8000/$mdm-query-links?resourceType=Patient
Authorization: Basic <base64(mdm-tutorial:password)>
The response is a Parameters resource. You should see two link entries — one for each source Patient — both pointing to the same goldenResourceId. The actual IDs on your server will differ from this example:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "total",
"valueDecimal": 2
},
{
"name": "self",
"valueUri": "http://localhost:8000/$mdm-query-links?resourceType=Patient&_offset=0&_count=20"
},
{
"name": "link",
"part": [
{ "name": "goldenResourceId", "valueString": "Patient/100" },
{ "name": "sourceResourceId", "valueString": "Patient/101" },
{ "name": "matchResult", "valueString": "MATCH" },
{ "name": "linkSource", "valueString": "AUTO" },
{ "name": "hadToCreateNewResource", "valueBoolean": true },
{ "name": "score", "valueDecimal": 1.0 }
]
},
{
"name": "link",
"part": [
{ "name": "goldenResourceId", "valueString": "Patient/100" },
{ "name": "sourceResourceId", "valueString": "Patient/102" },
{ "name": "matchResult", "valueString": "MATCH" },
{ "name": "linkSource", "valueString": "AUTO" },
{ "name": "hadToCreateNewResource", "valueBoolean": false },
{ "name": "score", "valueDecimal": 1.0 }
]
}
]
}
Key fields to note:
goldenResourceId (Patient/100 in this example). MDM created this Golden Resource automatically when the first patient arrived and reused it when the second patient matched.matchResult: MATCH means MDM was confident enough to link automatically, with no manual review needed.linkSource: AUTO means the link was created by MDM processing, as opposed to a data steward creating it manually.hadToCreateNewResource: true because there was no existing Golden Resource for this person yet. The second link has false because it reused the existing one.Make a note of the goldenResourceId value. You will use it in the next step.
Retrieve the Golden Resource by ID (using the value from the previous step in place of 100):
GET http://localhost:8000/Patient/100
Authorization: Basic <base64(mdm-tutorial:password)>
The response is a Patient resource that MDM created and manages. It looks like an ordinary Patient, but its meta.tag contains an entry that identifies it as a Golden Resource:
{
"resourceType": "Patient",
"id": "100",
"meta": {
"tag": [
{
"system": "http://hapifhir.io/fhir/NamingSystem/mdm-record-status",
"code": "GOLDEN_RECORD"
}
]
},
"identifier": [
{
"system": "http://hapifhir.io/fhir/NamingSystem/mdm-golden-resource-enterprise-id",
"value": "c0a9be58-1aa5-4b76-89b6-20c1b0f3fe11"
}
]
}
Note that there is no demographic data on the Golden Resource. This is because no survivorship rules were configured in this tutorial. Survivorship rules control which source record's data is applied when multiple records are linked — see MDM Survivorship for details.
You can also search for all Golden Patient resources in the repository using the _tag search parameter:
GET http://localhost:8000/Patient?_tag=http://hapifhir.io/fhir/NamingSystem/mdm-record-status|GOLDEN_RECORD
Authorization: Basic <base64(mdm-tutorial:password)>
In this tutorial you:
MATCH result.$mdm-query-links and fetched the Golden Resource directly by ID.POSSIBLE_MATCH links for cases that need human review. The MDM User Interface provides a data stewardship workflow for resolving these.matchFields is documented in Supported Match Algorithms.