Learn how to execute a SQL query to return features from a feature layer based on spatial and attribute criteria.
A feature layer can contain a large number of features stored in ArcGIS. You can query a layer to access a subset of its features using any combination of spatial and attribute criteria. You can control whether or not each feature's geometry is returned, as well as which attributes are included in the results. Queries allow you to return a well-defined subset of your hosted data for analysis or display in your ArcGIS Runtime app.
In this tutorial, you'll write code to perform SQL queries that return a subset of features in the LA County Parcel feature layer (containing over 2.4 million features). Features that meet the query criteria are selected in the map.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
-
The ArcGIS Runtime API for Qt is installed.
Steps
Open the project in Qt Creator
-
To start this tutorial, complete the Display a map tutorial or download and unzip the solution.
-
Open the display_a_map project in Qt Creator.
-
If you downloaded the solution, get an access token and set your API key.
An API Key gives your app access to secure resources used in this tutorial.
-
Go to the Create an API key tutorial to obtain a new API key access token using your ArcGIS Location Platform or ArcGIS Online account. Ensure that the following privilege is enabled: Location services > Basemaps > Basemap styles service. Copy the access token as it will be used in the next step.
-
In the Projects window, in the Sources folder, open the main.cpp file.
-
Modify the code to set the API key to the access token. Save and close the file.
main.cppUse dark colors for code blocks 43 44 45 46Change line // 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token. const QString accessToken = QString("");
-
Update the header file
This app will use various functions and member variables that need to be declared in the header file.
-
In Projects, double-click Headers > Display_a_map.h to open the file.
-
Forward declare the following classes.
Display_a_map.hUse dark colors for code blocks namespace ArcGISRuntime { class Map; class MapQuickView; class FeatureLayer; class ServiceFeatureTable;
-
Add the following code to define a function called
run
that will be invokable from the GUI.Query Display_a_map.hUse dark colors for code blocks public: explicit Display_a_map(QObject* parent = nullptr); ~Display_a_map() override; Q_INVOKABLE void runQuery(const QString& expression);
-
Declare the following private functions and member variables.
Display_a_map.hUse dark colors for code blocks private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); void setupViewpoint(); void addFeatureLayer(); void selectFeatures(); Esri::ArcGISRuntime::FeatureLayer* m_featureLayer = nullptr; Esri::ArcGISRuntime::ServiceFeatureTable* m_featureTable = nullptr;
Include header files in the source code
To create this app you will need to include several class header files from the ArcGIS Runtime Qt C++ API.
-
In Projects, double-click Sources > Display_a_map.cpp to open the file.
-
Add the following include statements. Each of these classes are needed for this tutorial.
Display_a_map.cppUse dark colors for code blocks #include "MapQuickView.h" #include <QUrl> #include "FeatureLayer.h" #include "SpatialReference.h" #include "ServiceFeatureTable.h" #include "Viewpoint.h" #include "Point.h" #include "QueryParameters.h" #include "FeatureQueryResult.h" #include "Feature.h" #include "SelectionProperties.h" #include <QColor> #include <QList> #include <memory>
Add a feature layer, query features, and select results
You will add three functions to add a feature layer from ArcGIS online, execute a query of that layer, and create a features list from the query result.
-
Add code to create the
add
function. This function adds the LA_County_Parcels feature layer hosted on ArcGIS Online to the map.Feature Layer Display_a_map.cppUse dark colors for code blocks void Display_a_map::setupViewpoint() { const Point center(-118.80543, 34.02700, SpatialReference::wgs84()); const Viewpoint viewpoint(center, 100000.0); m_mapView->setViewpoint(viewpoint); } void Display_a_map::addFeatureLayer() { // Create a ServiceFeatureTable from a QUrl. m_featureTable = new ServiceFeatureTable(QUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0"), this); // Create the feature layer using the feature table. m_featureLayer = new FeatureLayer(m_featureTable, this); // Add the feature layer to the map. m_map->operationalLayers()->append(m_featureLayer); }
-
Add the following function to implement the query. The
run
function executes a query of the parcels layer. This function creates aQuery QueryParameters
object that includes the currently visible map extent and a SQL expression, and then executes the query on the parcels table. Note that the SQL expression will come from aCombo
that you will implement in a coming step.Box Display_a_map.cppUse dark colors for code blocks void Display_a_map::addFeatureLayer() { // Create a ServiceFeatureTable from a QUrl. m_featureTable = new ServiceFeatureTable(QUrl("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0"), this); // Create the feature layer using the feature table. m_featureLayer = new FeatureLayer(m_featureTable, this); // Add the feature layer to the map. m_map->operationalLayers()->append(m_featureLayer); } void Display_a_map::runQuery(const QString& expression) { if (!m_featureTable) return; // Create a query parameter object and set the WhereClause. QueryParameters queryParams; queryParams.setGeometry(m_mapView->currentViewpoint(ViewpointType::BoundingGeometry).targetGeometry().extent()); queryParams.setWhereClause(expression); m_featureTable->queryFeatures(queryParams); }
-
Next, add the
select
function. When a query completes, this code iterates the returned results and adds those features to a list. That list is then used to select features in the parcels layer.Features Display_a_map.cppUse dark colors for code blocks void Display_a_map::runQuery(const QString& expression) { if (!m_featureTable) return; // Create a query parameter object and set the WhereClause. QueryParameters queryParams; queryParams.setGeometry(m_mapView->currentViewpoint(ViewpointType::BoundingGeometry).targetGeometry().extent()); queryParams.setWhereClause(expression); m_featureTable->queryFeatures(queryParams); } void Display_a_map::selectFeatures() { connect(m_featureTable, &ServiceFeatureTable::queryFeaturesCompleted, this, [this](QUuid, FeatureQueryResult* rawQueryResult) { if (!rawQueryResult) return; // Wrap the FeatureQueryResult in a unique_ptr to manage the memory effectively. auto queryResult = std::unique_ptr<FeatureQueryResult>(rawQueryResult); // Clear any existing selection. m_featureLayer->clearSelection(); QList<Feature*> features; // Iterate over the result object. while(queryResult->iterator().hasNext()) { Feature* feature = queryResult->iterator().next(this); // Add each feature to the list. features.append(feature); } // Select features. m_featureLayer->selectFeatures(features); }); }
-
By default, selected features in the map view are displayed in cyan. Modify the
set
function to call your new functions and also set the color for displaying selected parcel layer features (or any other selection) in your map view. Then save the file.Map View Display_a_map.cppUse dark colors for code blocks // Set the view (created in QML) void Display_a_map::setMapView(MapQuickView* mapView) { if (!mapView || mapView == m_mapView) { return; } m_mapView = mapView; m_mapView->setMap(m_map); addFeatureLayer(); selectFeatures(); m_mapView->setSelectionProperties(SelectionProperties(QColor(Qt::yellow)));
Show a list of query expressions for the user to choose from
You will create a UI that allows the user to choose from a list of predefined query expressions. The expressions are presented in a Combo
control and when the user makes a choice, the expression is passed to the run
method to find parcels that meet the selected criterion within the currently visible map extent.
-
In Projects, double-click Resources > qml\qml.qrc/qml/Display_a_mapForm.qml to open the file.
-
Add the following code to create a
Combo
control to execute a predefined query expression.Box Display_a_map.qmlUse dark colors for code blocks // Declare the C++ instance that creates the map etc., and supply the view. Display_a_map { id: model mapView: view } ComboBox { id: queryComboBox anchors { left: parent.left top: parent.top margins: 15 } property int bestWidth: implicitWidth width: bestWidth + indicator.width + leftPadding + rightPadding model: ["Choose a SQL where clause", "UseType = 'Government'", "UseType = 'Residential'", "UseType = 'Irrigated Farm'", "TaxRateArea = 10853", "TaxRateArea = 10860", "Roll_LandValue > 1000000", "Roll_LandValue < 1000000"] onCurrentTextChanged: { model.runQuery(queryComboBox.currentText) } }
-
Press Ctrl + R to run the app.
The app loads with the map centered on the Santa Monica Mountains in California with the parcels feature layer displayed. Choose an attribute expression, and parcels in the current extent that meet the selected criteria will display in the specified selection color.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: