ArcGIS Runtime SDK for macOS

Search for content

Portals can contain a huge amount of information. To help your users find the information they want to work with, you can add searching to your app. Searching can allow users to find information in different ways, for example, by searching for the groups that include a keyword, or finding all portal items that are web maps having specific tags.

Portal administrators can configure a number of settings to highlight specific content to users, such as the set of available basemaps,the content featured in the portal homepage and gallery, and the featured groups for the organization. Learn how to easily find featured basemaps, content, and groups.

Searching is done from the AGSPortal class. Publicly accessible items and groups can be accessed without any authentication, but to find items that are secured, a user with access to the item must be authenticated with the portal. See Access the ArcGIS Platform for more information about authenticating with a portal.

Search by defining query parameters

The API provides a flexible, generic search, along with some convenience methods to help you perform common portal searches.

Find portal items by keyword

To search for portal items using a keyword, construct a query that includes the keyword you want to search for. By default, the query will return portal items that include the keyword in any of the common fields of a portal item, including the title, tags, description, and type. The results of the query can be iterated.

Create a AGSPortalQueryParameters object and pass the keyword you want to search for into the constructor as the query parameter. Then pass the AGSPortalQueryParameters to the Portal:findItemsWithQueryParameters method. The resulting AGSPortalQueryResultSet should contain all of the portal items that contain the keyword in any of the searched fields.

let portal = AGSPortal(url: URL(string:"https://myportal.maps.arcgis.com/")! , loginRequired: false)
let queryParameters = AGSPortalQueryParameters(query: "san francisco")
 portal.findItems(with: queryParameters) { (resultSet, error) in
    if let error = error  {
        print(error)
        return
    }
    //process the resultSet
}

Note:

Remember, only the items that are accessible to the authenticated user of the portal will be included in the search results. When a user is not authenticated, only publicly shared items are found.

By default, the result set contains only the first 10 results but provides a convenient way to fetch subsequent sets of results if required. To learn more about working with large result sets, see Display many search results.

For a full list of the default fields used for searching, and complete information on constructing portal query strings, see the ArcGIS Online Search reference.

Order the search results

If there are more than a few results, you may want to help your user narrow down the results to find items of most interest. Your app can show the most recently updated results to the user first, sorting search results by the date they were last modified, in descending order.

queryParameters.sortField = "modified"
queryParameters.sortOrder = AGSPortalQuerySortOrder.descending

Results can be sorted in either ascending or descending order, by portal item fields such as the title, date of creation or date last modified, type, and owner. For a full list of sort fields, see ArcGIS Online Search.

Find items by type

You can restrict the results of a search to be a specific type or types of content; for example, you can search to find only web maps.

Create an AGSPortalQueryParameters object and pass the text you want to search for into the constructor. Then pass the AGSPortalQueryParameters to the AGSPortal.findItemsWithQueryParameters method. The resulting AGSPortalQueryResultSet should contain all of the portal items that contain the keyword in any of the searched fields.

let portal = AGSPortal(url: URL(string: "https://geoportal.mycompany.com")!, loginRequired: false)
portal.credential = AGSCredential(user: "username", password: "password")
let portalQueryParameters = AGSPortalQueryParameters(forItemsOf: AGSPortalItemType.webMap, withSearch: "san francisco")
 portal.findItems(with: portalQueryParameters) { (resultSet, error) -> Void in
    if let error = error  {
        print(error)
        return
    }

    //process the resultSet
}

If you want to find results of more than one type of portal item, you can do this by defining your query string.

Find groups by keyword

You can find groups by using a keyword in a similar way as it is used when finding portal items. For groups, the default fields searched include title, description, and tags (as for portal items), but also include owner.

let portalQueryParams = AGSPortalQueryParameters(forGroupsWithOwner: "ownername", title: "esri_demographics")
portal.findGroups(with: portalQueryParams) {(resultSet, error) -> Void in
    if let error = error {
        print(error)
        return
    }
         resultSet?.results?.forEach { (result) in
        if let portalGroup = result as? AGSPortalGroup {
            print(portalGroup.title ?? "No Title")
        }
    }
}

Find items in a known group

After a search for groups, you might want to list all of the items shared with those groups. Alternatively, you might want to list the items in a group returned from the authenticated users list of groups. If a search result set contains at least one group, to find all the items in that group, issue a second search using the group ID as part of the second query.

The code below continues from the previous example, by creating a second AGSPortalQueryParameters object, using the AGSPortalGroup objects from the initial search to set the group ID in the forItemsInGroup property, and then calling the AGSPortal.findItemsWithQueryParameters method to perform the second search.

let portalQueryParams = AGSPortalQueryParameters(forGroupsWithOwner: "ownername", title: "esri_demographics")
portal.findGroups(with: portalQueryParams) {[weak self](resultSet, error) -> Void in
    if let error = error {
        print(error)
        return
    }
     resultSet?.results?.forEach { (result) in
    if let portalGroup = result as? AGSPortalGroup {
        let portalQueryParameters = AGSPortalQueryParameters(forItemsInGroup: portalGroup.groupID!)
        self?.portal.findItems(with: portalQueryParameters, completion: { (resultSet, error) -> Void in
            if let error = error  {
                print(error)
                return
            }
                         resultSet?.results?.forEach { (result) in
                if let portalItem = result as? AGSPortalItem {
                    print(portalItem.title)
                }
            }
        })
    }
}

Find items by ID

If you already know the ID of a portal item, you can search for it by using that ID. You might find this technique useful if your app is closed while displaying a specific item—you can save the ID and fetch the item again to ensure the item is still accessible and all the properties are up-to-date, and use this information to restore the state of the app. If the search returns no results, then the item may no longer be available; for example, the owner may have changed the access permissions, and your app can react accordingly.

let portalQueryParameters = AGSPortalQueryParameters(forItemWithID: "1966ef409a344d089b001df85332608f")
 portal.findItems(with: portalQueryParameters) { (resultSet, error) -> Void in
    if let error = error  {
        print(error)
        return
    }
         resultSet?.results?.forEach { (result) in
        if let portalItem = result as? AGSPortalItem {
            print(portalItem.title)
        }
    }
}

You can also directly retrieve an AGSPortalItem by ID by passing a loaded AGSPortal and the ID to the AGSPortalItem constructor. Upon loading the AGSPortalItem it's properties can then be accessed.

let portalItem = AGSPortalItem(portal: portal, itemID: "c10191950210418eb9ec226019e18967")
portalItem.load(completion: { (error) -> Void in
    if let error = error  {
        print(error)
        return
    }
    //portalItem loaded
})

Define a query

If you need to search for items using more complex criteria, you can build a query to satisfy that criteria making use of multiple predicates, Boolean operators, ranges, and wildcards. You could, for example, build a query that finds items that are web maps, owned by the user "esri", with either of the tags "atlantic" or "pacific".

let portalQueryParameters = AGSPortalQueryParameters(query: "type:\"web map\" AND owner:esri AND tags:(pacific OR atlantic)")

Adding specific criteria can be especially useful when you are localizing your app, as you can limit results to a specific culture.

let portalQueryParameters = AGSPortalQueryParameters(query: "culture:fr-FR AND type:\"map service\"")

Tip:

You can also search using ranges of dates that items were created and last modified, using the created and modified fields of a portal item. However, be aware that portal searches use UNIX epoch dates (defined as the number of seconds that have elapsed since midnight January 1, 1970), as noted in the ArcGIS Online Search reference.

Search for featured basemaps, content, and groups

Portal administrators can configure a number of settings to highlight specific content to users. Configurable settings include the set of available basemaps, content featured in the portal homepage and gallery, and featured groups for the organization.

Get Home page and Gallery featured content

Administrators can configure two groups that contain featured content to show in different situations. The portal gallery can be populated either with the contents of a group, or with the top 100 most-viewed items. The homepage of the organization can also display featured content from a chosen group, and the maximum number of items displayed can be separately configured. Depending on the type of content that is featured, you may want your app to display the same featured items as shown in the website. For example, if the featured items are web maps, app users may want to browse a list of these maps, and then open them.

To search for the items displayed as homepage featured content, create a query using the AGSPortalInfo.homePageFeaturedContentGroupQuery property to set the query string. Use the query to find the group containing the featured content, and then perform a second search to find the items shared with that group.

let portalInfo = portal.portalInfo
portalQueryParameters = AGSPortalQueryParameters(query: (portalInfo?.homePageFeaturedContentGroupQuery)!)
self.portal.findGroups(with: portalQueryParameters) {[weak self](resultSet, error) -> Void in
    if let error = error  {
        print(error)
        return
    }
         resultSet?.results?.forEach { (result) in
        guard let portalGroup = result as? AGSPortalGroup, let groupID = portalGroup.groupID else  { return }
        let groupPortalQueryParameters = AGSPortalQueryParameters(forItemsInGroup: groupID)
        self?.portal.findItems(with: groupPortalQueryParameters, completion: { (resultSet, error) -> Void in
            if let error = error  {
                print(error)
                return
            }
                         resultSet?.results?.forEach { (result) in
                if let portalItem = result as? AGSPortalItem {
                    print(portalItem.title)
                }
            }
        })
    }
}

Get a list of configured basemaps

Many apps allow a user to change the basemap used to provide context for other data shown in a map. Portal administrators can configure the list of basemaps they want to be available to a user of a portal by sharing web maps into a specific group.

guard let portalInfo = portal.portalInfo else {return}
guard let basemapGalleryGroupQuery = portal.portalInfo?.basemapGalleryGroupQuery else { return }
 //set the portal query parameters
portalQueryParameters = AGSPortalQueryParameters(query: (basemapGalleryGroupQuery))
 //find the groups
portal.findGroups(with: portalQueryParameters) { (resultSet, error) in
    if let error = error  {
        print(error)
        return
    }
         resultSet?.results?.forEach { (result) in
        if let portalGroup = result as? AGSPortalGroup {
            print(portalGroup.title ?? "No Title")
        }
    }
}

For each web map in the result set, you can show the thumbnail and title of the item in a gallery or list. You can easily display a web map from the selected item by using its ID.

Additionally, you can use another predefined query (AGSPortalInfo.basemapGalleryGroupQuery) to find out the basemaps group for a portal if required, and from there you can list the items in that group.

Get featured groups

A list of featured groups can be configured to appear on the Groups and My Organization pages of the website. You can find out these groups, and in turn can get the contents as you would for any other group.

guard let portalInfo = portal.portalInfo else {return}
guard let query = portalInfo.featuredGroupsQueries?[0] else {return}
 //set the portal query parameters
portalQueryParameters = AGSPortalQueryParameters(query: query)
 //find the groups
portal.findGroups(with: portalQueryParameters) {(resultSet, error) -> Void in
    if let error = error  {
        print(error)
        return
    }
         resultSet?.results?.forEach { (result) in
        if let portalGroup = result as? AGSPortalGroup {
            print(portalGroup.title ?? "No Title")
        }
    }
}

Again, predefined query strings are available for the set of groups. Unlike the other predefined queries mentioned above, there are multiple queries used to find all of the groups. You can get a list of queries from the portal, each of which should return a single featured group.

Display many search results

Searches may return just a few results, or many thousands of results. To reduce network traffic and memory , search results are returned in batches (by default, only the first 10 are returned), along with a count of the total results found on the portal.

Often, the required item is in the first set of results, but your app can let the user decide if they need to see more items, for example, by scrolling past the end of a list, switching to the next page of results, or by tapping a button. You can easily issue another query to find the next set of results, as the result set from your first query constructs the correct subsequent query for you.

The code below uses creates a AGSPortalQueryParameters, sets the initial query, and calls the AGSPortal:findItemsWithQueryParameters method. After iterating through the initial results, the AGSPortalQueryParameters:nextQueryParameters is used to get the correct query to find the next set of results (you can check the Query method to find out how this works). If this query is not null, then a second call to findItemsWithQueryParameters is made. This pattern is repeated until nextQueryParameters method returns nil, indicating there are no more results to fetch.

portalQueryParameters = AGSPortalQueryParameters(query: "global rainfall")
 while portalQueryParameters != nil  {
    portal.findItems(with: portalQueryParameters, completion: { (resultSet, error) in
        if let error = error  {
            print(error)
            return
        }
                 resultSet?.results?.forEach { (result) in
            print(result)
        }
        portalQueryParameters = resultSet?.nextQueryParameters
    })
}

If you want to retrieve results in larger batches, use AGSPortalQueryParams:limit to change the batch size.