Skip to content

Learn how to execute a SQL query to access polygon features from a feature layer .

Use the selector to choose a SQL where clause to query and display features.

A feature layer can contain a large number of features stored in ArcGIS . To access a subset of the features, you can execute either a SQL or spatial query, or both at the same time. You can return feature attributes , geometry , or both attributes and geometry for each record. SQL and spatial queries are useful when you want to access only a subset of your hosted data.

In this tutorial, you will perform server-side SQL queries to return a subset of features in the LA County Parcel feature layer . The feature layer contains over 2.4 million features. The resulting features are displayed as graphics on the map.

Prerequisites

Steps

Create a new pen

  1. To get started, either complete the Display a map tutorial or .

Get an access token

You need an access token with the correct privileges to access the location services used in this tutorial.

  1. Go to the Create an API key tutorial and create an API key with the following privilege(s) :
    • Privileges
      • Location services > Basemaps
    • Item access
      • Note: If you are using your own custom data layer for this tutorial, you need to grant the API key credentials access to the layer item. Learn more in Item access privileges.
  2. In CodePen, set the apiKey property on the global esriConfig variable to your access token.
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };

To learn about other ways to get an access token, go to Types of authentication.

Create a SQL selector

ArcGIS feature layers support a standard SQL query where clause. Use a Calcite Select component to provide a list of SQL queries for the LA County Parcels feature layer .

  1. Add a Calcite Select component to the top-right slot of the map. This component has child option components, each with a different SQL query.

    33 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    93 collapsed lines
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    queryFeatureLayer(viewElement.extent);
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    displayResults(results);
    })
    .catch((error) => {
    console.log(error.error);
    });
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    // Clear display
    viewElement.closePopup();
    viewElement.graphics.removeAll();
    // Add features to graphics layer
    viewElement.graphics.addMany(results.features);
    }
    </script>
    </body>
    </html>
  2. Verify that the select component is created.

Add modules and event listeners

  1. Add a <script> tag in the <body> following the <arcgis-map> component. Use $arcgis.import() to add the FeatureLayer module.

    Use the document.querySelector() method to access the map, select, and the default option components. Create a whereClause variable to store the first option value.

    47 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    </script>
    5 collapsed lines
    </body>
    </html>
  2. Wait for the map to be ready with viewOnReady.

    47 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    </script>
    5 collapsed lines
    </body>
    </html>
  3. Create an event listener to listen for the select component changes and update the whereClause variable to the selected value.

    57 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    });
    6 collapsed lines
    </script>
    </body>
    </html>

Create a feature layer to query

Use the FeatureLayer class to access the LA County Parcel feature layer . Since you are performing a server-side query, the feature layer does not need to be added to the map.

  1. Create a parcelLayer and set the url property to access the feature layer in the feature service.
    57 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    6 collapsed lines
    </script>
    </body>
    </html>

Execute a query

Use the queryFeatures method to perform a SQL query against the feature layer . The Query will be autocast when the method is called.

  1. Create a queryFeatureLayer function with extent parameter. Define a parcelQuery element and set the where property to the whereClause. Set the spatialProperty to only return features that intersect the geometry, which is restricted to the visible extent of the map. The outFields property will return only a subset of the attributes . Lastly, set returnGeometry to true so that the features can be displayed.

    66 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    }
    8 collapsed lines
    </script>
    </body>
    </html>
  2. Call the queryFeatures method on the parcelLayer using parcelQuery. To view the number of features returned, write the result length to the console. This will be updated in the next step.

    71 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    })
    .catch((error) => {
    console.log(error.error);
    });
    }
    40 collapsed lines
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    // Clear display
    viewElement.closePopup();
    viewElement.graphics.removeAll();
    // Add features to graphics layer
    viewElement.graphics.addMany(results.features);
    }
    </script>
    </body>
    </html>
  3. Update the event handler to call the queryFeatureLayer function when the selector changes.

    59 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    queryFeatureLayer(viewElement.extent);
    });
    71 collapsed lines
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    displayResults(results);
    })
    .catch((error) => {
    console.log(error.error);
    });
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    // Clear display
    viewElement.closePopup();
    viewElement.graphics.removeAll();
    // Add features to graphics layer
    viewElement.graphics.addMany(results.features);
    }
    </script>
    </body>
    </html>
  4. At the top-right, click Run. Choose a SQL query from the selector. At the bottom left, click Console to view the number of features returned from each query.

Display features

To display the features returned from the SQL query, add them to the view as polygon graphics . Define a pop-up also so the attributes can be displayed when features are clicked.

  1. Create a displayResults function with results as a parameter. Define a symbol and popupTemplate variable to style and display a pop-up for polygon graphics . The attributes referenced match the outFields specified in the query earlier.

    91 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    queryFeatureLayer(viewElement.extent);
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    displayResults(results);
    })
    .catch((error) => {
    console.log(error.error);
    });
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    }
    7 collapsed lines
    </script>
    </body>
    </html>
  2. Assign the symbol and popupTemplate elements to each feature returned from the query.

    110 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    queryFeatureLayer(viewElement.extent);
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    displayResults(results);
    })
    .catch((error) => {
    console.log(error.error);
    });
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    8 collapsed lines
    }
    </script>
    </body>
    </html>
  3. Clear the existing graphics and pop-up , and then add the new features returned to the view.

    101 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    // Clear display
    viewElement.closePopup();
    viewElement.graphics.removeAll();
    // Add features to graphics layer
    viewElement.graphics.addMany(results.features);
    9 collapsed lines
    }
    </script>
    </body>
    </html>
  4. Update the queryFeatureLayer function to call the displayResults function. Remove the console.log.

    83 collapsed lines
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>ArcGIS Maps SDK for JavaScript Tutorials: Query a feature layer (SQL)</title>
    <style>
    html,
    body {
    height: 100%;
    margin: 0;
    }
    </style>
    <script>
    var esriConfig = {
    apiKey: "YOUR_ACCESS_TOKEN",
    };
    </script>
    <!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    </head>
    <body>
    <arcgis-map basemap="arcgis/topographic" center="-118.805, 34.020" zoom="13">
    <arcgis-zoom slot="top-left"></arcgis-zoom>
    <calcite-select id="sqlSelect" slot="top-right">
    <calcite-option id="defaultOption" value="1=0" label="Choose a SQL where clause..."></calcite-option>
    <calcite-option value="UseType = 'Residential'" label="UseType = 'Residential'"></calcite-option>
    <calcite-option value="UseType = 'Government'" label="UseType = 'Government'"></calcite-option>
    <calcite-option value="UseType = 'Irrigated Farm'" label="UseType = 'Irrigated Farm'"></calcite-option>
    <calcite-option value="TaxRateArea = 10853" label="TaxRateArea = 10853"></calcite-option>
    <calcite-option value="TaxRateArea = 10860" label="TaxRateArea = 10860"></calcite-option>
    <calcite-option value="TaxRateArea = 08637" label="TaxRateArea = 08637"></calcite-option>
    <calcite-option value="Roll_LandValue > 1000000" label="Roll_LandValue > 1000000"></calcite-option>
    <calcite-option value="Roll_LandValue < 1000000" label="Roll_LandValue < 1000000"></calcite-option>
    </calcite-select>
    </arcgis-map>
    <script type="module">
    const FeatureLayer = await $arcgis.import("@arcgis/core/layers/FeatureLayer.js");
    const viewElement = document.querySelector("arcgis-map");
    const selectFilter = document.querySelector("#sqlSelect");
    const defaultOption = document.querySelector("#defaultOption");
    let whereClause = defaultOption.value;
    await viewElement.viewOnReady();
    // Event listener
    selectFilter.addEventListener("calciteSelectChange", (event) => {
    whereClause = event.target.value;
    queryFeatureLayer(viewElement.extent);
    });
    // Get query layer and set up query
    const parcelLayer = new FeatureLayer({
    url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/LA_County_Parcels/FeatureServer/0",
    });
    function queryFeatureLayer(extent) {
    const parcelQuery = {
    where: whereClause, // Set by select element
    spatialRelationship: "intersects", // Relationship operation to apply
    geometry: extent, // Restricted to visible extent of the map
    outFields: ["APN", "UseType", "TaxRateCity", "Roll_LandValue"], // Attributes to return
    returnGeometry: true,
    };
    parcelLayer
    .queryFeatures(parcelQuery)
    .then((results) => {
    console.log("Feature count: " + results.features.length);
    displayResults(results);
    })
    .catch((error) => {
    console.log(error.error);
    });
    42 collapsed lines
    }
    function displayResults(results) {
    // Create a blue polygon
    const symbol = {
    type: "simple-fill",
    color: [20, 130, 200, 0.5],
    outline: {
    color: "white",
    width: 0.5,
    },
    };
    const popupTemplate = {
    title: "Parcel {APN}",
    content:
    "Type: {UseType} <br> Land value: {Roll_LandValue} <br> Tax Rate City: {TaxRateCity}",
    };
    // Assign styles and popup to features
    results.features.map((feature) => {
    feature.symbol = symbol;
    feature.popupTemplate = popupTemplate;
    return feature;
    });
    // Clear display
    viewElement.closePopup();
    viewElement.graphics.removeAll();
    // Add features to graphics layer
    viewElement.graphics.addMany(results.features);
    }
    </script>
    </body>
    </html>

Run the app

In CodePen, run your code to display the map.

When the map displays, you should be able to choose a SQL query from the selector. The resulting features will be added to the map as polygon graphics . The SQL query is applied to the visible extent of the map.

What’s next?

Learn how to use additional SDK features and ArcGIS services in these tutorials: