Create mobile geodatabase

View on GitHubSample viewer app

Create and share a mobile geodatabase.

screenshot

Use case

A mobile geodatabase is a collection of various types of GIS datasets contained in a single file (.geodatabase) on disk that can store, query, and manage spatial and nonspatial data. Mobile geodatabases are stored in a SQLite database and can contain up to 2 TB of portable data. Users can create, edit and share mobile geodatabases across ArcGIS Pro, ArcGIS Maps SDK for Native Apps, or any SQL software. These mobile geodatabases support both viewing and editing and enable new offline editing workflows that don’t require a feature service.

For example, a user would like to track the location of their device at various intervals to generate a heat map of the most visited locations. The user can add each location as a feature to a table and generate a mobile geodatabase. The user can then instantly share the mobile geodatabase to ArcGIS Pro to generate a heat map using the recorded locations stored as a geodatabase feature table.

How to use the sample

Select "Create new .geodatabase" to create a new mobile geodatabase in a temporary directory. Click or tap on the map to add features to the mobile geodatabase. Select "View feature table" to view the contents of the geodatabase feature table. Select "Clear features" to remove all features from the geodatabase feature table. Select "Close .geodatabase" to save and close the geodatabase so it is ready to be shared or uploaded to ArcGIS Online.

How it works

  1. Create a new Geodatabase at a given path that does not already exist with the Geodatabase::createAsync() static method.
  2. Create a TableDescription and add a list of FieldDescriptions to the table description.
  3. Create a GeodatabaseFeatureTable from the geodatabase with the TableDescription using Geodatabase::createTableAsync(TableDescription* tableDescription).
  4. Create an ArcGISFeature on a selected map point using FeatureTable::createFeature(const QVariantMap &attributes, const Geometry& geometry, QObject* parent = nullptr).
  5. Add the feature to the table using FeatureTable::addFeatureAsync(Feature* feature)
  6. Each feature added to the feature table is committed to the mobile geodatabase file.
  7. Close the mobile geodatabase to safely share the ".geodatabase" file using Geodatabase::close()

Relevant API

  • ArcGISFeature
  • FeatureLayer
  • FeatureTable
  • FieldDescription
  • Geodatabase
  • GeodatabaseFeatureTable
  • TableDescription

Additional information

Learn more about mobile geodatabases and how to utilize them on the Mobile geodatabases page. The following mobile geodatabase behaviors are supported in ArcGIS Maps SDK for Native Apps: annotation, attachments, attribute rules, contingent values, dimensions, domains, feature-linked annotation, subtypes, utility network and relationship classes.

Visit ArcGIS field data types to learn more about the types of fields supported.

Tags

arcgis pro, database, feature, feature table, geodatabase, mobile geodatabase, sqlite

Sample Code

CreateMobileGeodatabase.cppCreateMobileGeodatabase.cppCreateMobileGeodatabase.hFeatureListModel.cppFeatureListModel.hCreateMobileGeodatabase.qml
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// [WriteFile Name=CreateMobileGeodatabase, Category=Features]
// [Legal]
// Copyright 2022 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#ifdef PCH_BUILD
#include "pch.hpp"
#endif // PCH_BUILD

// sample headers
#include "CreateMobileGeodatabase.h"
#include "FeatureListModel.h"

// ArcGIS Maps SDK headers
#include "FeatureIterator.h"
#include "FeatureLayer.h"
#include "FeatureQueryResult.h"
#include "FieldDescription.h"
#include "FieldDescriptionListModel.h"
#include "Geodatabase.h"
#include "GeodatabaseFeatureTable.h"
#include "GeometryTypes.h"
#include "LayerListModel.h"
#include "Map.h"
#include "MapQuickView.h"
#include "MapTypes.h"
#include "Point.h"
#include "QueryParameters.h"
#include "ServiceTypes.h"
#include "SpatialReference.h"
#include "TableDescription.h"
#include "Viewpoint.h"

// Qt headers
#include <QFuture>

using namespace Esri::ArcGISRuntime;

CreateMobileGeodatabase::CreateMobileGeodatabase(QObject* parent /* = nullptr */):
  QObject(parent),
  m_map(new Map(BasemapStyle::ArcGISTopographic, this))
{
  // The FeatureListModel is a helper class created specifically for this sample to display all features in the table view
  m_featureListModel = new FeatureListModel(this);
}

CreateMobileGeodatabase::~CreateMobileGeodatabase() = default;

void CreateMobileGeodatabase::init()
{
  // Register the map view for QML
  qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
  qmlRegisterType<CreateMobileGeodatabase>("Esri.Samples", 1, 0, "CreateMobileGeodatabaseSample");
}

MapQuickView* CreateMobileGeodatabase::mapView() const
{
  return m_mapView;
}

// Set the view (created in QML)
void CreateMobileGeodatabase::setMapView(MapQuickView* mapView)
{
  if (!mapView || mapView == m_mapView)
    return;

  m_mapView = mapView;
  m_mapView->setMap(m_map);
  m_mapView->setViewpointAsync(Viewpoint(39.3238, -77.7332, 10'000));

  connect(m_mapView, &MapQuickView::mouseClicked, this, &CreateMobileGeodatabase::addFeature);

  emit mapViewChanged();
}

// Create a Geodatabase in an empty directory
void CreateMobileGeodatabase::createGeodatabase()
{
  m_gdbFilePath = QString{m_tempDir.path() + "/LocationHistory_%1.geodatabase"}.arg(QDateTime::currentSecsSinceEpoch() % 1000);
  emit gdbFilePathChanged();

  // We cannot overwrite an existing geodatabase
  if (QFile::exists(m_gdbFilePath))
    return;

  // Use static Geodatabase::createAsync with an empty file path
  Geodatabase::createAsync(m_gdbFilePath, this).then(this, [this](Geodatabase* geodatabase)
  {
    m_gdb = geodatabase;
    createTable();
  });
}

// Create a GeodatabaseFeatureTable from the new Geodatabase with a TableDescription
void CreateMobileGeodatabase::createTable()
{
  m_gdbOpen = true;
  emit gdbOpenChanged();

  // Create a TableDescription to define the GeodatabaseFeatureTable's attributes and fields
  TableDescription* tableDescription = new TableDescription("LocationHistory", SpatialReference::wgs84(), GeometryType::Point, this);
  tableDescription->setHasAttachments(false);
  tableDescription->setHasM(false);
  tableDescription->setHasZ(false);
  tableDescription->fieldDescriptions()->append(new FieldDescription("oid", FieldType::OID));
  tableDescription->fieldDescriptions()->append(new FieldDescription("collection_timestamp", FieldType::Date));

  m_gdb->createTableAsync(tableDescription, this).then(this, [this](GeodatabaseFeatureTable* gdbFeatureTableResult)
  {
    m_featureTable = gdbFeatureTableResult;

    FeatureLayer* featureLayer = new FeatureLayer(m_featureTable, this);
    m_map->operationalLayers()->append(featureLayer);
  });
}

// Close the Geodatabase so that it can be safely shared
void CreateMobileGeodatabase::closeGdb()
{
  if (!m_gdb)
    return;

  m_gdb->close();
  m_gdbOpen = false;

  m_map->operationalLayers()->clear();
  m_featureListModel->clear();

  m_featureCount = 0;

  emit gdbOpenChanged();
  emit featureCountChanged();
}

void CreateMobileGeodatabase::addFeature(QMouseEvent& mouseEvent)
{
  if (!m_featureTable)
    return;

  const Point mousePoint = m_mapView->screenToLocation(mouseEvent.position().x(), mouseEvent.position().y());
  QVariantMap attributes = {};
  attributes.insert("collection_timestamp", QDateTime::currentDateTime());
  Feature* feature = m_featureTable->createFeature(attributes, mousePoint, this);

  m_featureTable->addFeatureAsync(feature).then(this, [this, feature]()
  {
    m_featureListModel->addFeature(feature);
    emit featureListModelChanged();

    m_featureCount = static_cast<int>(m_featureTable->numberOfFeatures());
    emit featureCountChanged();
  });
}

void CreateMobileGeodatabase::deleteFeatures()
{
  QueryParameters params;
  params.setWhereClause("1=1");

  m_featureTable->queryFeaturesAsync(params).then(this, [this](FeatureQueryResult* rawQueryResult)
  {
    // Cast the FeatureQueryResult to a unique pointer to delete it when it goes out of scope
    auto queryResults = std::unique_ptr<FeatureQueryResult>(rawQueryResult);
    FeatureIterator resultIterator = queryResults->iterator();

    auto deleteFeaturesFuture = m_featureTable->deleteFeaturesAsync(resultIterator.features());
    Q_UNUSED(deleteFeaturesFuture)
    m_featureCount = 0;
    emit featureCountChanged();
  });
}

void CreateMobileGeodatabase::clearFeatures()
{
  if (m_featureTable->numberOfFeatures() > 0)
    deleteFeatures();

  m_featureListModel->clear();
}

FeatureListModel* CreateMobileGeodatabase::featureListModel() const
{
  return m_featureListModel;
}

QString CreateMobileGeodatabase::gdbFilePath() const
{
  return m_gdbFilePath;
}

int CreateMobileGeodatabase::featureCount() const
{
  return m_featureCount;
}

bool CreateMobileGeodatabase::gdbOpen() const
{
  return m_gdbOpen;
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.