Query

A query provides the ability to return a subset of features from a dataset based on any combination of attribute, spatial, and temporal (time) criteria.

  • Attribute criteria are defined with a standard SQL expression based on the available attribute fields.
  • Spatial criteria use a geometry and a spatial relationship (within, contains, intersect, and so on).
  • A temporal filter can be defined using a single date or time, or a range.

You can also perform queries to return related features, a feature count, an extent containing all features meeting your criteria, or statistical information about a dataset.

How query works

Query criteria is defined using a query parameters object. This is where you specify the attribute, spatial, and/or temporal inputs. Most ArcGIS Runtime queries take query parameters as an input to define the query criteria as well as some preferences for the results. When the query is executed against a specific dataset (feature table), results are returned as a collection of features.

A query does not require that each type of criteria be defined. Query criteria are only evaluated if explicitly defined (missing temporal criteria, for example, means not to filter the results according to time).

Relevant classes and members in the API ref

Query parameters

Query parameters define the query criteria using:

  • An SQL expression for attribute criteria
  • Geometry and a spatial relationship for spatial criteria
  • A date/time or a range of dates/times for temporal criteria

Some spatial relationships you can define for the query include:

  • Intersects: part of a feature is contained in the geometry.
  • Touches: a feature touches the border of the geometry.
  • Crosses: a feature crosses the geometry.
  • Within: a feature is completely enclosed by the geometry.
  • Contains: part or all of a feature is contained within the geometry.

The query parameters can be used in a standard query to return features, or in queries that return a feature count or extent. You can also use the query parameters to make a selection in the map showing the features that match the criteria.

Specialized query parameters are used for queries that return statistics or related features. In addition to query criteria, these query parameters define things like the type of statistics to return or the relationships to evaluate.

This example uses spatial criteria to find features inside a polygon. Instead of executing a query on the AGSFeatureTable, however, the query parameters are simply passed to the AGSFeatureLayer to display features that meet the criteria as a new selection.

                                                                                                                                         
// --- Edit ---

func addFeature(point: AGSPoint!) {
         guard let damageTable = damageTable else {
        return}
    }
         //Create attributes for the feature
    var attributes = [String:Any]()
    attributes["typdamage"] = "Minor"
    attributes["primcause"] = "Earthquake"
         //Create a new feature from the attributes and the point
    let feature = damageTable?.createFeature(attributes: attributes, geometry: point)
     //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         damageTable?.add(arcgisFeature) {(error: Error?) -> Void in
        if let error = error {
            print("Error while adding feature :: \(error.localizedDescription)")
            return
        }
        //apply edits
    }
}



//Loop through the features
features.forEach {(feature) in
         //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         //change the attribute value and..
    arcgisFeature.attributes["typdamage"] = "Inaccessible"
         //move it a little North
    guard let currentLoc = arcgisFeature.geometry as? AGSPoint else { return }
         let updatedLoc = AGSPoint(x: currentLoc.x, y: currentLoc.y + 50000, spatialReference: self?.map.spatialReference)
    arcgisFeature.geometry = updatedLoc

    //Update the feature
    self?.damageTable?.update(arcgisFeature, completion: { (error:Error?) -> Void in
                 if let error = error {
            print("Error while updating feature :: \(error.localizedDescription)")
            return
        }
                     //Apply Edits
        self?.damageTable?.applyEdits(completion: { (featureEditResults: [AGSFeatureEditResult]?, error: Error?)-> Void in
            if let error = error {
                print("Error while applying edit :: \(error.localizedDescription)")
                return
            }
            print("Apply Edits successful")
        })
    })

}



//Loop through the features
features.forEach {(feature) in
         //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         //Delete feature
    self?.damageTable?.delete(arcgisFeature) { [weak self] (error: Error?) -> Void in
        if let error = error {
            print("Error while deleting feature :: \(error.localizedDescription)")
            return
        }
                     //Apply Edits
        self?.damageTable?.applyEdits { (featureEditResults: [AGSFeatureEditResult]?, error: Error?) -> Void in
            if let error = error {
                print("Error while applying edit :: \(error.localizedDescription)")
                return
            }
            print("Apply Edits successful")
        }
    }
}


// --- Query ---


//Create a buffer from the point
let searchGeometry = AGSGeometryEngine.bufferGeometry(point, byDistance: 5000)
//Create a Query
let params = AGSQueryParameters()
params.geometry = searchGeometry
params.spatialRelationship = .within
//Select features based on query
damageFeatureLayer?.selectFeatures(withQuery: params, mode: .new) { (queryResult:AGSFeatureQueryResult?, error:Error?) -> Void in
    if let error = error {
        print(error)
        return
    }
    if let result = queryResult {
        print("\(result.featureEnumerator().allObjects.count) feature(s) selected")
    }
}



// TODO:



// TODO:



// TODO:



// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
 self.mapView.identifyLayer(self.parksFeatureLayer, screenPoint: self.screenPoint, tolerance: 12, returnPopupsOnly: false, maximumResults: 10) { (identifyLayerResult: AGSIdentifyLayerResult) -> Void in
    if let error = identifyLayerResult.error {
        print(error)
        return
    }

    //process the identifyLayerResult ...
    // get the layer identified and cast it to FeatureLayer
    if let theLayer = identifyLayerResult.layerContent as? AGSFeatureLayer {

        // iterate each identified GeoElement in the results
        for geoElement in identifyLayerResult.geoElements
        {
            // select this feature in the feature layer
            if let feature = geoElement as? AGSFeature {theLayer.select(feature)}
        }
    }
}

Query results

Query results typically provide a collection of features. You can iterate the result features to display them on the map, read their attributes, and so on. A query for statistics returns a collection of records that describe the requested statistics for features in the dataset. Queries for feature count or extent return a number and an envelope respectively.

Geometry for the query results can be returned in a specified spatial reference by specifying the output spatial reference in the query parameters. If a spatial reference is not specified, results will be returned in the spatial reference of the dataset. Most often, you will need the result features in the same spatial reference as your app's map.

You can also set a maximum number of features to return in the result. This is useful in situations where you might only need a subset of features that meet your criteria. It may also improve performance by limiting the amount of information returned with the result.

Identify

Identify is like a shortcut for a spatial query. It allows you to quickly answer the question: what is here? It gives users a quick way to explore and learn about the map or scene content by tapping or clicking. Information returned from an identify operation can be shown in pop-ups or other UI components in your app. Unlike a query, you can't provide attribute or time criteria to filter results. You can, however, return all geoelements (from all layers) at the specified location.

                                                                                                                                         
// --- Edit ---

func addFeature(point: AGSPoint!) {
         guard let damageTable = damageTable else {
        return}
    }
         //Create attributes for the feature
    var attributes = [String:Any]()
    attributes["typdamage"] = "Minor"
    attributes["primcause"] = "Earthquake"
         //Create a new feature from the attributes and the point
    let feature = damageTable?.createFeature(attributes: attributes, geometry: point)
     //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         damageTable?.add(arcgisFeature) {(error: Error?) -> Void in
        if let error = error {
            print("Error while adding feature :: \(error.localizedDescription)")
            return
        }
        //apply edits
    }
}



//Loop through the features
features.forEach {(feature) in
         //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         //change the attribute value and..
    arcgisFeature.attributes["typdamage"] = "Inaccessible"
         //move it a little North
    guard let currentLoc = arcgisFeature.geometry as? AGSPoint else { return }
         let updatedLoc = AGSPoint(x: currentLoc.x, y: currentLoc.y + 50000, spatialReference: self?.map.spatialReference)
    arcgisFeature.geometry = updatedLoc

    //Update the feature
    self?.damageTable?.update(arcgisFeature, completion: { (error:Error?) -> Void in
                 if let error = error {
            print("Error while updating feature :: \(error.localizedDescription)")
            return
        }
                     //Apply Edits
        self?.damageTable?.applyEdits(completion: { (featureEditResults: [AGSFeatureEditResult]?, error: Error?)-> Void in
            if let error = error {
                print("Error while applying edit :: \(error.localizedDescription)")
                return
            }
            print("Apply Edits successful")
        })
    })

}



//Loop through the features
features.forEach {(feature) in
         //check it is an AGSArcGISFeature
    guard let arcgisFeature = feature as? AGSArcGISFeature else {
        return
    }
         //Delete feature
    self?.damageTable?.delete(arcgisFeature) { [weak self] (error: Error?) -> Void in
        if let error = error {
            print("Error while deleting feature :: \(error.localizedDescription)")
            return
        }
                     //Apply Edits
        self?.damageTable?.applyEdits { (featureEditResults: [AGSFeatureEditResult]?, error: Error?) -> Void in
            if let error = error {
                print("Error while applying edit :: \(error.localizedDescription)")
                return
            }
            print("Apply Edits successful")
        }
    }
}


// --- Query ---


//Create a buffer from the point
let searchGeometry = AGSGeometryEngine.bufferGeometry(point, byDistance: 5000)
//Create a Query
let params = AGSQueryParameters()
params.geometry = searchGeometry
params.spatialRelationship = .within
//Select features based on query
damageFeatureLayer?.selectFeatures(withQuery: params, mode: .new) { (queryResult:AGSFeatureQueryResult?, error:Error?) -> Void in
    if let error = error {
        print(error)
        return
    }
    if let result = queryResult {
        print("\(result.featureEnumerator().allObjects.count) feature(s) selected")
    }
}



// TODO:



// TODO:



// TODO:



// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
 self.mapView.identifyLayer(self.parksFeatureLayer, screenPoint: self.screenPoint, tolerance: 12, returnPopupsOnly: false, maximumResults: 10) { (identifyLayerResult: AGSIdentifyLayerResult) -> Void in
    if let error = identifyLayerResult.error {
        print(error)
        return
    }

    //process the identifyLayerResult ...
    // get the layer identified and cast it to FeatureLayer
    if let theLayer = identifyLayerResult.layerContent as? AGSFeatureLayer {

        // iterate each identified GeoElement in the results
        for geoElement in identifyLayerResult.geoElements
        {
            // select this feature in the feature layer
            if let feature = geoElement as? AGSFeature {theLayer.select(feature)}
        }
    }
}

Samples