Query feature table

View on GitHub

Find features in a feature table which match an SQL query.

Query feature table options Query feature table results

Use case

Query expressions can be used in ArcGIS to select a subset of features from a feature table. This is most useful in large or complicated data sets. A possible use case might be on a feature table marking the location of street furniture through a city. A user may wish to query by a TYPE column to return "benches". In this sample, we query a U.S. state by STATE_NAME from a feature table containing all U.S. states.

How to use the sample

Input the name of a U.S. state into the text field. A query is performed and the matching features are highlighted or an error is returned.

How it works

  1. Create an ServiceFeatureTable using the URL of a feature service.
  2. Create QueryParameters with a whereClause specified.
  3. Perform the query using FeatureTable.queryFeatures(using:) on the service feature table.
  4. When complete, the query will return a FeatureQueryResult which can be iterated over to get the matching features.

Relevant API

  • FeatureLayer
  • FeatureQueryResult
  • QueryParameters
  • ServiceFeatureTable

About the data

This sample uses U.S. State polygon features from the USA 2016 Daytime Population feature service.

Tags

query, search

Sample Code

QueryFeatureTableView.swift
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
// Copyright 2023 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
//
//   https://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.

import ArcGIS
import SwiftUI

struct QueryFeatureTableView: View {
    @StateObject private var model = Model()

    /// The error shown in the error alert.
    @State private var error: Error?

    /// The text in the search bar.
    @State private var searchBarText = ""

    var body: some View {
        MapViewReader { mapViewProxy in
            MapView(map: model.map)
                .errorAlert(presentingError: $error)
                // Makes the search bar.
                .searchable(text: $searchBarText, prompt: "Search state names")
                .autocorrectionDisabled()
                .onSubmit(of: .search) {
                    model.currentQuery = searchBarText
                }
                // A task that runs when the query text changes.
                .task(id: model.currentQuery) {
                    // Makes sure we have a query string.
                    guard !model.currentQuery.isEmpty else { return }
                    // Unselects all selected features.
                    model.featureLayer.clearSelection()
                    // Makes the query parameters and executes the query.
                    let queryParameters = QueryParameters()
                    queryParameters.whereClause = "upper(STATE_NAME) LIKE '%\(model.currentQuery.uppercased())%'"
                    do {
                        let queryResult = try await model.featureTable.queryFeatures(using: queryParameters)
                        let queryResultFeatures = Array(queryResult.features())
                        if !queryResultFeatures.isEmpty {
                            // Displays the selection.
                            model.featureLayer.selectFeatures(queryResultFeatures)
                            // Zooms to the selected features.
                            if let combinedExtent = GeometryEngine.combineExtents(of: queryResultFeatures.compactMap(\.geometry)) {
                                await mapViewProxy.setViewpointGeometry(combinedExtent, padding: 25)
                            }
                        } else {
                            // If the query returned no features then zooms
                            // to the extent of the layer.
                            if let layerExtent = model.featureLayer.fullExtent {
                                await mapViewProxy.setViewpointGeometry(layerExtent, padding: 50)
                            }
                        }
                    } catch {
                        // Displays the error as an alert.
                        self.error = error
                    }
                }
        }
    }
}

private extension QueryFeatureTableView {
    class Model: ObservableObject {
        /// A map with a topographic basemap style.
        let map: Map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(
                center: Point(x: -11e6, y: 5e6, spatialReference: .webMercator),
                scale: 9e7
            )
            return map
        }()

        /// The text used in the query.
        @Published var currentQuery = ""

        /// A feature table of US Daytime Population Census Tracts.
        let featureTable = ServiceFeatureTable(
            item: PortalItem(
                portal: .arcGISOnline(connection: .anonymous),
                id: .daytimePopulation
            )
        )

        /// A feature layer created from the service feature table.
        let featureLayer: FeatureLayer

        init() {
            // Creates a feature layer from feature table.
            featureLayer = FeatureLayer(featureTable: featureTable)
            // Shows the layer at all scales.
            featureLayer.minScale = nil
            featureLayer.maxScale = nil

            // Sets a new renderer on the feature layer.
            let lineSymbol = SimpleLineSymbol(style: .solid, color: .black, width: 1)
            let fillSymbol = SimpleFillSymbol(style: .solid, color: .yellow.withAlphaComponent(0.5), outline: lineSymbol)
            featureLayer.renderer = SimpleRenderer(symbol: fillSymbol)
            // Adds the feature layer to the map.
            map.addOperationalLayer(featureLayer)
        }
    }
}

private extension PortalItem.ID {
    /// The portal item ID of a USA 2016 Daytime Population feature layer.
    static var daytimePopulation: Self { Self("f01f0eda766344e29f42031e7bfb7d04")! }
}

#Preview {
    NavigationStack {
        QueryFeatureTableView()
    }
}

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