Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Current »

Adds functionality to store demographic information on the server. See /wiki/spaces/MTB/pages/1934819724 and Demographic Survey Categories (somewhat outdated).

Type Checking

Currently, there is no type checking on demographic answer values, so all values are stored as strings. Type checking is a V2 goal.

App-Level vs. Study-Level

Routes are available for both app-level and study-level demographics. The idea is that some basic demographics might be collected during app onboarding which is not associated with a particular study, and then additional demographics data might be collected by a particular study within the app.

Routes

Saving

POST /v5/studies/{studyId}/participants/{userId}/demographics

Save/overwrite all demographics for a user

Study-level, posted on the user’s behalf (by researcher, study coordinator)

POST /v5/studies/{studyId}/participants/self/demographics

Save/overwrite all demographics for a user

Study-level, posted by the user

POST /v1/apps/self/participants/{userId}/demographics

Save/overwrite all demographics for a user

App-level, posted on the user’s behalf (by app admin)

POST /v1/apps/self/participants/self/demographics

Save/overwrite all demographics for a user

App-level, posted by the user

POST /v5/studies/{studyId}/participants/{userId}/demographics/assessment

Save/overwrite all demographics for a user

Study-level, posted on the user’s behalf (by researcher, study coordinator)

Uses the assessment JSON model

POST /v5/studies/{studyId}/participants/self/demographics/assessment

Save/overwrite all demographics for a user

Study-level, posted by the user

Uses the assessment JSON model

POST /v1/apps/self/participants/{userId}/demographics/assessment

Save/overwrite all demographics for a user

App-level, posted on the user’s behalf (by app admin)

Uses the assessment JSON model

POST /v1/apps/self/participants/self/demographics/assessment

Save/overwrite all demographics for a user

App-level, posted by the user

Uses the assessment JSON model

Deleting

DELETE /v5/studies/{studyId}/participants/{userId}/demographics/{demographicId}

Deletes a specific demographic (single category) for a particular user

Study-level, done by researcher or study coordinator

DELETE /v1/apps/self/participants/{userId}/demographics/{demographicId}

Deletes a specific demographic (single category) for a particular user

App-level, done by app admin

DELETE /v5/studies/{studyId}/participants/{userId}/demographics

Deletes all of a user’s demographics

Study-level, done by researcher or study coordinator

DELETE /v1/apps/self/participants/{userId}/demographics

Deletes all of a user’s demographics

App-level, done by app admin

Fetching

GET /v5/studies/{studyId}/participants/{userId}/demographics

Fetches all demographics for a user

Study-level, done by researcher/study-coordinator

GET /v1/apps/self/participants/{userId}/demographics

Fetches all demographics for a user

App-level, done by app admin

GET /v5/studies/{studyId}/participants/demographics

Fetches all study-level demographics for all users within a study

Study-level, done by researcher/study-coordinator

GET /v1/apps/self/participants/demographics

Fetches all app-level demographics for all users within an app

App-level, done by app admin

JSON Format

Unless otherwise stated, routes use the following schema (for a single user):

{
  "userId": (read only) <string>,
  "demographics": {
    (category name): {
      "id": (guid) (read only) <string>,
      "multipleSelect": <bool>,
      "values": [
        <any>
      ]
      "units": <string>
    },
    ...
  }
}

Example:

{
  "userId": "userId1",
  "demographics": {
    "height": {
      "id": "guid1",
      "multipleSelect": false,
      "values": [
        72.0
      ]
      "units": "m"
    },
    "race": {
      "id": "guid2",
      "multipleSelect": true,
      "values": [
        "Asian",
        "Native Hawaiian or Other Pacific Islander"
      ]
    }
  }
}

Certain routes use an assessment response model for demographic input:

{
  "stepHistory": [
    {
      "identifier": <string> (category name),
      "answerType": {
        "type": <string> (this field is only checked to see if it contains "array")
      },
      "value": <array or single value, any type>
    }
  ]
}

Although other fields may be included in the normal assessment model, all other fields are discarded for demographics use. “type” is only used to determine whether to deserialize “value” as an array or single value.

Example:

{
  "stepHistory": [
    {
      "identifier": "height",
      "answerType": {
        "type": "float"
      },
      "value": 72.0
    },
    {
      "identifier": "race",
      "answerType": {
        "type": "array"
      },
      "value": [
        "Asian",
        "Native Hawaiian or Other Pacific Islander"
      ]
    }
  ]
}

Internal model

SQL:

CREATE TABLE `DemographicsUsers` (
    `id` varchar(60) NOT NULL,
    `studyId` varchar(60) NULL,
    `appId` varchar(60) NOT NULL,
    `userId` varchar(255) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY (`studyId`, `appId`, `userId`),
    CONSTRAINT `DemographicUser-Account-Constraint` FOREIGN KEY (`userId`) REFERENCES `Accounts` (`id`) ON DELETE CASCADE,
    CONSTRAINT `DemographicUser-Study-Constraint` FOREIGN KEY (`studyId`, `appId`) REFERENCES `Substudies` (`id`, `studyId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `Demographics` (
    `id` varchar(60) NOT NULL,
    `demographicUserId` varchar(60) NOT NULL,
    `categoryName` varchar(768) NOT NULL,
    `multipleSelect` boolean NOT NULL,
    `units` varchar(512) NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY (`demographicUserId`, `categoryName`),
    CONSTRAINT `Demographic-DemographicUser-Constraint` FOREIGN KEY (`demographicUserId`) REFERENCES `DemographicsUsers` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `DemographicsValues` (
    `demographicId` varchar(60) NOT NULL,
    `value` varchar(1024) NOT NULL,
    CONSTRAINT `DemographicValue-Demographic-Constraint` FOREIGN KEY (`demographicId`) REFERENCES `Demographics` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

3 tables are used because each table has a one-to-many relationship with the table below it, both intuitively and in SQL, and this nested format is much simpler with multiple tables. It also allows convenient grouping by userId for a better JSON format.

  • DemographicsUsers: maps to Java class DemographicUser

    • Contains all demographics for a single user

    • One-to-many with Demographics

  • Demographics: maps to Java class Demographic

    • Contains all values for a single demographic category for a single user

    • One-to-many with DemographicsValues

  • DemographicsValues: maps to Java class DemographicValue

    • Contains a single value in a demographic category

App-level demographics are represented with a null studyId.

  • No labels