Building > Quick Guides > Database
Managing databases used by CHT applications
CouchDB (and PouchDB in the browser) is a JSON-based NoSQL datastore that we use to store our data. While unlike SQL databases there is no enforced schema, code still follows conventions, and this document aims to describe the schema as defined by how our code operates.
In this document “record” means a JSON object that resides in CouchDB or PouchDB.
Property | Description | Required by |
---|---|---|
_id | CouchDB’s unique identifier of the record | all records |
_rev | CouchDB’s revision marker | all records |
type | The general type of the document, see below | all user-created* documents |
reported_date | Numerical timestamp of when the document is first created | all user-created documents |
Contacts are either places (e.g. clinic), groupings (e.g. family) or people (e.g. a patient or CHW).
The type
property of contact records depends on the version of Medic you are running:
type
of contacts is contact
, and the configured type is in the contact_type
property.district_hospital
, health_centre
and clinic
and one people type person
. These place names are often meaningless (hence the configurable contact hierarchy in later versions) to the configured project, and are textually (ie in the UI not in data structures) renamed to mean other things. For example, as clinic
is the lowest level it is often used to represent a family.Represent either an actual physical location such as a clinic, or a grouping such as a family or region.
Unless a place is at the top of the hierarchy it has a parent
place.
Each location has a primary contact, which is a person
contact stored in the contact
property.
People are both patients in the system and users of the system, such as CHWs or Nurses. Users have additional records marking them as users of the system (see User below).
People always have a parent
place.
Contacts store their parent hierarchy as a minified hierarchical structure, which records the _id
of each parent up until the top of the hierarchy:
{
type: 'person',
name: 'A patient',
parent: {
_id: 'clinic-id',
parent: {
_id: 'health_centre-id',
parent: {
_id: 'district_hospital-id'
}
}
}
}
Generally when contacts are used in the app they are first “hydrated”, with the rest of the information filled in from their parent’s place documents:
{
type: 'person',
name: 'A patient',
parent: {
_id: 'clinic-id',
name: 'A clinic',
reported_date: 1234,
... // etc
parent: {
_id: 'health_centre-id',
name: 'A Health Centre',
reported_date: 1134,
... // etc
parent: {
_id: 'district_hospital-id',
name: 'THE District Hospital',
reported_date: 1034,
... // etc
}
}
}
}
See Also: Document hydration
As of version 3.10, you can connect contacts with other documents via the linked_docs
property. This allows the app to have access to these linked documents when the contact is used.
Like the parent hierarchy, linked docs are stored as a minified object, where every linked doc is identified by a string tag and the UUID of the document it represents.
{
type: 'person',
name: 'A patient',
parent: {
_id: 'clinic-id',
},
linked_docs: {
custom_tag1: 'some-contact-id',
custom_tag2: 'other-contact-id',
custom_tag3: 'report-id',
... // etc
},
}
Linked docs are shallowly “hydrated” along with the parent hierarchy:
{
type: 'person',
name: 'A patient',
parent: {
_id: 'clinic-id',
name: 'A clinic',
reported_date: 1234,
... // etc
parent: {
_id: 'health_centre-id',
name: 'A Health Centre',
reported_date: 1134,
... // etc
parent: {
_id: 'district_hospital-id',
name: 'THE District Hospital',
reported_date: 1034,
... // etc
}
}
},
linked_docs: {
custom_tag1: {
_id: 'some-contact-id',
name: 'some contact',
type: 'person',
parent: { _id: 'other-clinic' },
reported_date: 4569,
... // etc
},
custom_tag2: {
_id: 'other-contact-id',
name: 'other contact',
type: 'clinic',
parent: { _id: 'health_center' },
... // etc
},
custom_tag3: {
_id: 'report-id',
form: 'FORM',
contact: { _id: 'submitter-id' },
... // etc
},
},
}
Reports are created by users filling out and submitting forms, as well as sending in SMS.
All reports:
data_record
typefields
propertyfrom
fieldform
fieldcontact
property, which is a minified version of the report author’s contact and its hierarchy (see above)Reports can and should be linked to a contact when possible. The report’s associated contact (sometimes called the report’s subject) can be either a person or place. The link between report and contact is established by defining one of the following properties within the report:
doc.fields.patient_id
, doc.fields.patient_uuid
, or doc.patient_id
doc.fields.place_id
or doc.place_id
.Additionally, SMS reports:
sms_message
property which contains, among other things, the raw SMScontact
property if the SMS comes from a phone number that does not have an associated contactAdditionally, XML reports:
content_type
property of xml
SMS forms are defined in application config.
XML forms are stored in the database and have:
_id
of form:<formname>
type
of form
XML forms are defined as XForm XML files
Users represent credentials and roles / permissions for accessing the application. This can either be:
User records have at least:
_id
of org.couchdb.user:<username>
name
which is the same as <username>
aboveroles
arrayThere are two slightly different copies of this record stored.
The record in the _users
database includes:
type
of user
The _users
database is what CouchDB uses for authentication and is only editable by administrative users, so is authoritative when it comes to roles and the like.
The medic
database stores a copy of roles and permissions along with:
type
of user-settings
contact_id
field that is the _id
of the person that the user is attached tofacility_id
field that is the _id
of the place that the user is attached toknown
field. If this field is true
, it means the user has logged in once. Otherwise, it will be undefined
.Note that SMS users do not have a users record: their phone number will be attached to a person
record, but they do not have a user because they do not access the application.
Users then, can be represented by up to 3 docs:
person
document that represents a physical human being in our hierarchy of places and peopleusers
document that represents authorisation and authentication information for physical people or authenticated external servicesuser-settings
document that ties the user
and person
documents togetherPartner configuration code running inside the Core Framework can cause tasks to appear within the Tasks tab. Each task in the tab is powered by a task document. Task documents are:
State | Description |
---|---|
Draft | Task has been calculated but it is scheduled in the future |
Ready | Task is currently showing to the user |
Cancelled | Task was not emitted when refreshing the requester’s data. Task has invalid partner emission. |
Completed | Task was emitted with { resolved: true } |
Failed | Task was never terminated and the endDate has past |
Attribute | Description |
---|---|
user | The user settings id of the user who calculated and created the document. Used for controlling replication. (eg. org.couchdb.user:agatha ) |
requester | The guid of the contact whose data brought about the creation of the document. Used for controlling cancellation. |
owner | The guid of the contact whose profile this task will appear on in the contact’s tab. |
forId | If completing a task’s action opens a form. Completing the form creates a report. forId is the guid of the contact information that will be passed into the form. For most forms, the resulting report will be associated with this contact. |
emission | Minified task data emitted from the partner code. |
stateHistory | Each time the state attribute changes, the time of the change is recorded in the state history. |
To understand the difference between a task requester and a task owner, kindly see the example below:
{
"_id": "task~org.couchdb.user:agatha~pregReport~pregnancy-facility-visit-reminder~2~523435132468",
"type": "task",
"authoredOn": 523435132468,
"user": "org.couchdb.user:agatha",
"requester": "requester-contact-guid",
"owner": "owner-contact-guid",
"state": "Ready",
"emission": {
"_id": "pregReport~pregnancy-facility-visit-reminder~2",
"forId": "for-contact-guid",
"dueDate": "2000-01-01",
"startDate": "1999-12-29",
"endDate": "2000-01-08",
"priority": "high",
"priorityLabel": "task.priority",
...
},
"stateHistory": [{
"state": "Ready",
"timestamp": 523435132468,
}],
}
Partner configuration code can configure targets to appear within the Targets/Analytics tab. Target documents are:
{
"_id": "target~2000-01~user-contact-guid~org.couchdb.user:agatha",
"type": "target",
"user": "org.couchdb.user:agatha",
"owner": "user-contact-guid",
"updated_date": 523435132468,
"targets": [
{
"id": "deaths-this-month",
...
"value": {
"pass": 0,
"total": 15
}
},
...
]
}
Managing databases used by CHT applications
Contact Pages: Customizing the fields, cards, and actions on profile pages
Targets: Definition of target widgets calculated and seen in the app
Tasks: Definition of tasks shown to app users
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.