- Intro
- Class Api
- Functional Api
- Advanced
- Access Control
- Permissions
- OperationStack
- Metrics
- Queries & Filters
- Catalogs & Collections
- Composing Workflows
- Developers
- Legacy
Catalogs and Collections
A Catalog defines a set of platform entities (items/users/groups/events etc) which can be searched. Catalogs can have futher subsets called Collections.
When executing queries, additional filters can be applied at the Catalog or Collection level.
While a Catalog can reference any set of platform entities, any individual Collection can only reference a single platform entity type (i.e. items vs groups)
Hub Sites utilize a Catalog to define what content is available on a site search. Catalogs are also used for Hub Projects and Hub Initiatives.
Any hierarchy of content between Sites, Initiatives and Projects must be manually maintained, and will not be automatic. This is typically done by organizing content by Groups, and then adding Project Catalog groups to their parent Initiative Catalog, and then up to the Site Catalog.
Catalogs associated with Hub Sites, Hub Initiatives and Hub Projects will all be stored in the .catalog
property of the item's data.json. If other applications want to leverage the Catalog system, we recommend storing the information in this same location.
The Catalog structure is expected to change over time so it's important to either fetch the Site/Project/Initiative via the cooresponding Class instances, or use the upgradeCatalogSchema(..)
function to ensure you are working with the latest structure before executing searches.
Interfaces
Defining a Catalog
Catalogs and Collections are defined using json structure, specified in typescript via the IHubCatalog
and IHubCollection
interfaces.
The Catalog defines a set of "scopes" for each resource type to be included in the Catalog. Each scope is an IQuery
object.
// Example Catalog setting the scope for "item" searches to content
// in a specific group OR owned by a specific user
const seventhStreetProjectCatalog: IHubCatalog = {
title: "Seventh Street Project",
schemaVersion: 1,
scopes: {
item: {
// IQuery applied when searching for `items`
targetEntity: "item",
operation: "OR",
filters: [
{
predicates: [
{
group: ["c4059b70af8d4773910a812f7d712dc8"],
},
],
},
{
predicates: [
{
owner: "data_mart",
},
],
},
],
},
},
collections: [],
};
Collections in Catalogs
A Collection is a subset of the Catalog, constrained to a single platform entity, specified by the targetEntity
property. The .scope
of a Collection is an IQuery
object which adds additional critera, creating the "subset".
// This example adds a collection, which adds additional constraints on top of
// the catalog itself.
//
// Searching the Web Maps collection will limit the search to items in the
// ("c4059b70af8d4773910a812f7d712dc8" group OR owned by data_mart) AND
// which have type:"Web Map" AND NOT type: "Web Mapping Application"
const seventhStreetProjectCatalog: IHubCatalog = {
title: "Seventh Street Project",
schemaVersion: 1,
scopes: {
item: {
// IQuery
targetEntity: "item",
filters: [
{
predicates: [
{
group: ["c4059b70af8d4773910a812f7d712dc8"],
},
],
},
{
predicates: [
{
owner: "data_mart",
},
],
},
],
},
},
collections: [
{
targetEntity: "item",
key: "webmaps",
label: "Web Maps",
scope: {
targetEntity: "item",
filters: [
{
predicates: [
{
type: {
any: ["Web Map"],
not: ["Web Mapping Application"],
},
},
],
},
],
},
},
],
};
Working with Catalogs
The Catalog
and Collection
classes are designed to simplify working with these structures, in particular, loading Catalogs from items, executing Catalog searches, getting a Collection from a Catalog, and executing Collection searches.
Searching a Site Catalog
import { Catalog } from "@esri/hub-common";
// Load the catalog for a specific site
const siteCatalog = await Catalog.init("https://opendata.dc.gov");
// alternatively an item id can be passed in
const projectCatalog = await Catalog.init("648149685cfd47f7b265d37d009a87dd");
// search for schools.
const itemResults = await siteCatalog.searchItems("schools");
const groupResults = await siteCatalog.searchGroups("schools");
const userResults = await siteCatalog.searchUsers("schools");
In the example above, no authentication information or server information has been provided, so the system assumes the backing server is ArcGIS Online. It will look up the Site item based on the url, and from that, load the Catalog. If an item id is passed in, it will simply fetch the item, and load the Catalog. In either case, schema upgrades are automatically applied, ensuring that the system is always operating with the latest version of the catalog structure.
Catalog Search "Scopes"
Although the Catalog specification supports many different entity searches (item, group, user, event etc ), and individual Catalog instance may not support all the entities. Attempting to search for an entity that does not have a scope defined, will result in an exception.
To determine what scopes are available, user the .availableScopes
property to get an array of them.
Search Options
All the search functions take an IHubSearchOptions
as the second parameter, and this is used to specify paging, sorting, aggregations and includes. Please see the IHubSearchOptions
documentation for more information.
Searching an ArcGIS Enterprise Site Catalog Example
const mgr = await ArcGISContextManager.init({
portalUrl: "https://myserver.com/gis",
});
const siteCatalog = Catalog.init(
"https://myserver.com/gis/apps/sites/#mysite",
mgr.context
);
const results = await siteCatalog.search("schools");
Passing Authentication
When a Catalog or Collection instance is created, the second parameter is an IArcGISContext
which holds authentication information. To create an IArcGISContext
, we use the ArcGISContextManager
class, and pass a UserSession
into it's .init
factory function.
A UserSession
be created directly, via oAuth, or from a JSAPI Identity Manager via the UserSession.fromCredential(...)
static method. Please see the ArcGIS REST JS Documentation. (Note: At this time ArcGISContextManager is only compabitle with REST-JS 3.x)
NOTE passing .authentication
or .requestOptions
on the IHubSearchOptions
will be ignored, and instead the context information help in the Catalog or Collection instance will be used.
const session = new UserSession({
username: "replacewithusername",
password: "replacewithpassword",
});
const mgr = await ArcGISContextManager.init({
portalUrl: "https://myserver.com/gis",
authentication: session,
});
const siteCatalog = Catalog.init(
"https://private-site-org.hub.arcgis.com",
mgr.context
);
// This will return any items the user has access to, matching "water"
// within the catalog
const results = siteCatalog.search("water");
Working with Collections
A Collection
defines a set of searchable platform resources, of a single type - i.e. Items OR Groups OR Users.
Further, Collections
within Catalogs
are expected to be constrained to the scope of their targetEntity
as defined at the Catalog level. Put another way, all collections in a Catalog should be subset's of the Catalog itself.
Operationally, this means that the IQuery
defined in Collection.scope
, must include the IQuery
that's defined at Catalog.scopes[collection.targetEntity]
. While this can be done manually, the Catalog class provides an abstraction to simplify this.
NOTE Unlike searching directly against the Catalog, a Collection can be defined for an entity that does not have a scope defined at the Catalog level. i.e. the Catalog may not have a user
scope defined, but there can be a Collection defined that targets the user
entity.
// Working from the Seventh Street Project catalog defined above
// we can initialize a Catalog and then use that to get the Web Map collection
const catalog = Catalog.fromJson(seventhStreetProjectCatalog);
// we can get the collection from the catalog via it's key property
const collection = catalog.getCollection("webmaps");
// searching the collection, constrains the search to the intersection
// of the set of entities defined by the Catalog's item scope, and the
// set of entities defined by the Collection's scope
const results = collection.search("water");
Using Catalog / Collection Json Directly
There are times when the application will have already fetched the Catalog or Collection json, or cases where a Collection needs to be created dynamically (i.e. for use in an Item Picker gallery)
In these scenarios use the .fromJson(...)
static method to create an instance of either class.
// Creating a Collection from Json
const myCollection = Collection.fromJson({
label: "Example Json Collection",
key: "example",
targetEntity: "item",
scope: {
filters: [
{
predicates: [
{
group: "aba30fb9f66c4d1ebf8a37d6130c722b",
typekeyword: "Solution Template",
},
],
},
],
},
});
const results = myCollection.search("Vision Zero");
Complex Queries
The examples so far have focused on passing a string into the .search(..)
method, but that method can also take an IQuery
which enables complex queries to be constructed. Please see the Queries and Filters Guide for more information.