Skip to content

Cloud Firestore Representation

Shobhit Agarwal edited this page Aug 13, 2020 · 13 revisions

This page describes how Ground data is structured in Cloud Firestore. For definitions of terminology used throughout this document, please refer to Key Concepts.

Collection hierarchy

Cloud Firestore databases are composed of collections (πŸ“) and documents (πŸ“„). Collections may contain one or more documents, which themselves may can contain other collections, and so on, ad infinitum. For a full explanation see Cloud Firestore Data Model.

Ground data is organized in Cloud Firestore as follows:

πŸ“‚ projects/
  πŸ“„ project001
    πŸ“‚ features/
      πŸ“„ feature001
    πŸ“‚ observations/
      πŸ“„ observation001
πŸ“‚ users/
  πŸ“„ user001

Where project001, feature001, observation001, etc., represent auto-generated UUIDs of zero or more related documents.

User-defined i18n

User-defined multilingual strings like title and description are stored as associative arrays keyed by ISO-639 language code.

Document structure

Projects

Path: /projects/${projectId}

Project settings, form definitions, and ACLs defined by project managers are stored in documents with the following structure:

{
  title: { 'en': 'Project title' },
  description: { 'en': 'Project description' },
  owner: 'user1234',
  layers: {
    'layer001': {
      name: { 'en': 'Layer name' },
      index: 1,
      defaultStyle: {
        color: '#rrggbb',
      },
      forms: {
        'form001': {
          elements: {
            'element001': {
              index: 0,
              label: { 'en': 'Question 1' },
              required: true,
              type: 'text_field'
            },
            'element002': {
              index: 1,
              label: { 'en': 'Question 2' },
              required: false,
              type: 'multiple_choice',
              cardinality: 'select_one',
              options: {
                option001: {
                  index: 0,
                  code: 'A',
                  label: { 'en': 'Option A' }
                },
                // ...
              }
            },
            // ...
          }
        }
      }
    }
  },
  acl: {
    user001: 'viewer',
    user002: 'contributor',
    user003: 'manager',
    // ...
  }
}

Features

Path: /projects/${projectId}/features/${featureId}

{
  caption: 'User-defined label',
  location: {
    latitude: -74.0060,
    longitude: 40.7128
  },
  layerId: 'layer1234'
}

Observations

Path: /projects/${projectId}/observations/${observationId}

{
  featureId: 'feature123'
  formId: 'form001',
  responses: {
    'element001': 'Response text',  // For 'text_field  elements.
    'element002': ['A', 'B'],       // For 'multiple_choice' elements.
    // ...
  }
  created: <AUDIT_INFO>,
  lastModified: <AUDIT_INFO>
}

Where <AUDIT_INFO> contains user details and timestamps for creation and last modification:

{
  user: {
    id: ...,
    displayName: ...,
    email: ...
  },
  clientTimestamp: ...,
  serverTimestamp: ...
}

Responses

Format for photo responses:

uploaded_media/{project_id}/{form_id}/{feature_id}/{UUID.jpg}