You are here:
Archive SDK Data Query
The Archive SDK Data Query enables programmatic access to archived data in the Archive app. These data queries automate business processes, support third-party system integrations, create custom views and reports, and cross-reference archived data with active records.
Archive Widget and Archive Search provide use options for manual data retrieval. The SDK offers advanced capabilities, such as query parameters, filters, and pagination, for direct data access via code.
SDK Data Query features include:
- Search archived records by using specified criteria.
- Use partial matching with an asterisk (*).
- Return large datasets in batches of up to 1,000 records per page.
- Apply up to six filters to refine your results.
These objects are filtered out and aren't searchable via the SDK.
FeedHistoryShareFeedRelationShare
To maintain optimal performance, and verify that only relevant archived data is returned, these objects are excluded from searches.
To access archived files, use the Archive Widget or Archive Search.
Archive SDK Data Query Methods
To define how you query archived data, set the method provided by the Archive SDK.
- Accessing Archive Data—The methods within
ArchiverAccessorare designed to interact with archived records. Then you can build queries and retrieve data stored in the Archive product. - Defining Query Operations—These signatures tell you what kinds of queries you can perform by using the SDK, such as global searches and filtered queries.
- Guiding Usage—By examining method signatures, developers can understand the inputs and outputs required for their implementations.
performArchiverGlobalSearch Method
This method indicates the functionality to perform a global search on archived data.
Query Parameters
The Data Query SDK uses several parameters to refine your search. Some parameters are required, while others are optional. Understanding how to configure each parameter helps you get the most accurate and relevant results.
- Object Name—Specifies the type of Salesforce object to query.
For example,
string sObjectName = 'Account'specifies that the query targets Account records.This parameter is mandatory.
Note Each query targets a single object. Use separate queries to retrieve data from multiple objects. - Search Filters—Filters that narrow search results based on field conditions.
- Field Name—The field that you want to filter by, such as
NameorCreatedDate - Value or List of Values—The specific value or values that you want to
match
Example: Single Value Filter
SF_Archive.SearchFilter filter = new SF_Archive.SearchFilter('Name', 'test');This query returns records where the Name field matches the string "test".
Example: Multiple Value FilterSF_Archive.SearchFilter filter = new SF_Archive.SearchFilter('Status', new List<String>{'Open', 'Closed'});This query returns records where the Status field matches the strings "Open" or "Closed."
Handling Empty or Null Values—To search for records where a field is empty or null, you can add an empty string ("") to the List of Values.Example:
This query returns Case records where the Subject field is either empty or null.List<SearchFilter> filters = new List<SearchFilter>(); filters.add(new SearchFilter('Subject', ''));Search filter limits:
- Queries must have at least 1 filter per query.
- Queries can have up to 6 filters, combined with
ANDlogic, per query. - Filters are combined using
ANDlogic by default.ORlogic isn't currently supported. - A filter's value list can't exceed 1,000 items.
This parameter is mandatory.
- Field Name—The field that you want to filter by, such as
- Date Filters—If you want to search based on dates, use the
DateRangeparameter and the mandatory filters.DateRangefilters records by fields such asArchiveDate,CreatedDate, orModifiedDate.Example: Date Filter for Specific Date Query
Date todayDate = Date.today(); Date jan1st2024 = Date.newInstance(2024, 1, 1); DateRange dateRange = new DateRange('archive_date', jan1st2024, todayDate);This query returns records archived between January 1, 2024 and today.
Example: Date Filter for Multiple Date Range
List<SF_Archive.SearchFilter> filters = new List<SF_Archive.SearchFilter>(); SF_Archive.SearchFilter filter = new SF_Archive.SearchFilter('Name', 'test'); filters.add(filter); string sObjectName = 'Account'; Date myDate = Date.newInstance(2024, 1, 11); // January 11, 2024 Date myDate2 = Date.newInstance(2023, 12, 25); // December 12, 2023 SF_Archive.dateRange range = new SF_Archive.dateRange('CreatedDate', myDate, myDate); SF_Archive.dateRange range2 = new SF_Archive.dateRange('CreatedDate', myDate2, myDate2); list<SF_Archive.dateRange> ranges = new list<SF_Archive.dateRange> {range, range2}; SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch(sObjectName, filters, ranges);This query returns records archived between December 12, 2023 and January 11, 2024.
Date filter recommendations:
- To search based on the Archive Date, add the
archive_datedate field. - Use the Apex date format: MM/DD/YYYY.
This parameter is optional.
- To search based on the Archive Date, add the
- Returned Fields—Specify fields to include in the results. If not specified, all
fields are returned.
Example: Return Specific Fields
List<string> fields = new List<string>{'Name', 'CreatedDate'};This query returns only the
NameandCreatedDatefields for each record.This parameter is optional.
- Page Size—Sets the number of records per query. The default number of records
per query is 25, and the maximum is 1,000.
Example: Custom Page Size
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch('Account', filters, 100, fields);This query returns 100 records per page.
This parameter is optional.Note Exceeding 1,000 records in your query triggers a run-time error. - Sorting Direction—Sorts results by a field, such as
CreatedDate.- Ascending (
asc): Oldest to newest. - Descending (
desc): Newest to oldest.Example: Sorting Query
SortingDirection sortingDirection = new SortingDirection('desc');This query returns records sorted in descending order based on their
CreatedDate.This parameter is optional.
- Ascending (
getNextPage Method
If the results don't all fit on the same page, this method calls the next page.
ScrollId Parameter
Use pagination to return large datasets by fetching results in pages of up to 1,000 records.
To set up the pagination workflow, perform the initial query, use the scrollId
from the response to fetch subsequent pages, and continue until
scrollId = '-1'..
Example: Fetch Results with Pagination
// Perform initial search query
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch('Account',
filters, 100, fields);
// Get the search response
SF_Archive.ArchiverAccessorSearchResponse searchResponse = res.getSearchResponseMap();
// Process first page of results
system.debug('Total result count: ' + searchResponse.totalResultCount);
system.debug('Records: ' + searchResponse.records);
// Fetch next page using the scrollId
if (searchResponse.scrollId != '-1') {
SF_Archive.ArchiverAccessorResponse nextPageRes = SF_Archive.ArchiverAccessor.getNextPage(searchResponse.scroll);
SF_Archive.ArchiverAccessorSearchResponse nextPageResponse = nextPageRes.getSearchResponseMap();
system.debug('Next Page Records: ' + nextPageResponse.records);
}Access the Methods
To find the method signatures, go to Apex Classes under Setup. Open the
ArchiverAccessor class. Locate all methods listed under the
performArchiverGlobalSearch namespace.
Sample Data Query
This example retrieves Account records by using these
conditions.
- Fields:
Name,CreatedDate - Limit: 100 records per page
- Name: Contains string "test"
- Sorting: Descending by
CreatedDate
List<SF_Archive.SearchFilter> filters = new List<SF_Archive.SearchFilter>();
SF_Archive.SearchFilter filter = new SF_Archive.SearchFilter('Name', 'test');
filters.add(filter);
List<string> fields = new List<string>{'Name', 'CreatedDate'};
SortingDirection sortingDirection = new SortingDirection('desc');
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch('Account',
filters, 100, fields, sortingDirection);
Troubleshoot Common Errors
| Error Code | Description | Resolution |
|---|---|---|
INTERNAL_ERROR |
An unexpected failure occurred. | Contact support with error details. |
RESOURCE_LIMIT_ERROR |
Exceeded pagination or query size limits. | Reduce page size or refine search filters. |
VALIDATION_ERROR |
Missing or invalid search criteria. | Make sure that all fields and fields are valid. |
Additional Recommendations
- Monitor your API usage to avoid hitting limits.
- To cast the response to an object, serialize it into JSON and then deserialize it back into an object.
- Verify that fields are enabled and accessible.
- Double-check all query parameters.
- For unresolved issues, contact Archive SDK Support with detailed logs.
For more information, see Archive SDK Testing.
- Archive SDK Data Query—Code Example
In this code example, a filter, a date range, and an archive search request are validated through the status code in the Archive app. - Archive SDK Data Query—Sample Use Case 1
This example use case shows how to build and customize a widget that displays High Priority Accounts in the Archive app. - Archive SDK Data Query—Sample Use Case 2
This example use case shows how Archive SDK handles tasks without exceeding governor limits, such as CPU limits or Timeout callouts, in the Archive app.
Archive SDK Data Query—Code Example
In this code example, a filter, a date range, and an archive search request are validated through the status code in the Archive app.
A getNextPage call following (scrollId != -1) is
included because the size of the results is limited in the
performArchiverGlobalSearch call.
string sObjectName = 'Account';
list<SF_Archive.SearchFilter>request = new list<SF_Archive.SearchFilter>();
SF_Archive.SearchFilter filter1 = new SF_Archive.SearchFilter('Name', 'test');
request.add(filter1);
SF_Archive.dateRange range = new SF_Archive.dateRange('CreatedDate', system.today()-150, system.today());
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch(sObjectName, request, range);
if(res.getStatusCode() == 200){
system.debug('code: ' + res.getStatuscode());
SF_Archive.ArchiverAccessorSearchResponse searchResponse = res.getSearchResponseMap();
system.debug('count: '+ searchResponse.totalResultCount);
system.debug('scrollid: '+ searchResponse.scrollId);
system.debug('list size: '+ searchResponse.records.size());
string scrollId = searchResponse.scrollId;
integer page = 1;
while(scrollId != '-1'){
page++;
SF_Archive.ArchiverAccessorResponse secondPage =
SF_Archive.ArchiverAccessor.getNextPage(searchResponse.scrollId);
if(secondPage.getStatusCode() == 200){
SF_Archive.ArchiverAccessorSearchResponse searchResponse2 = secondPage.getSearchResponseMap();
scrollId = searchResponse2.scrollId;
system.debug('count: '+ searchResponse2.totalResultCount);
system.debug('scrollid: '+ searchResponse2.scrollId);
system.debug('list size: '+ searchResponse2.records.size());
system.debug('page number: '+ page);
} else{
system.debug('response is != 200: '+ secondPage.getStatusCode());
system.debug('body: '+ secondPage.getBody());
break;
}
}
} else {
system.debug('status code erorr|: '+ res.getStatusCode());
system.debug('status code message|: '+ res.getErrorMessage());
}Archive SDK Data Query—Sample Use Case 1
This example use case shows how to build and customize a widget that displays High Priority Accounts in the Archive app.
Use Case
Your business requires that the Tier 3 Support Team has access to view archived Cases with a high-priority status.
This example shows how to:
- Create a customized Lightning Web Component (LWC).
- Pull archived data by using the data query SDK.
- Apply the filter (High Priority). Note Other filters can be customized by referring to the code in Archive SDK Data Query — Code Example.
This example is limited to 25 records. The SDK enables you to set the results at 1,000 per page. The default is 25, with the option of pagination through the results.
Widget Displaying High-Priority Cases
Sample SdkUseCaseWidget.js
In this code example, the parameter is AccountRecordId.
import { LightningElement, api, track } from 'lwc';
import getCases from '@salesforce/apex/ArchiveSdk.getCases';
export default class SampleSdkUseCaseWidget extends LightningElement {
@api recordId;
columns = [
{ label: 'Case Number', fieldName: 'caseNumber', type: 'text', cellAttributes: {alignment: 'center'}},
{ label: 'Subject', fieldName: 'subject', type: 'text' , cellAttributes: {alignment: 'center'}, },
{ label: 'Priority', fieldName: 'priority', type: 'text', cellAttributes: {alignment: 'center'}, },
{ label: 'Status', fieldName: 'status', type: 'text', cellAttributes: {alignment: 'center'}, }
];
@track records;
@track data
@track _loading;
async connectedCallback() {
this._loading = true;
try {
const result = await getCases({parentId: this.recordId})
this.records = result;
this._loading = false;
} catch (error) {
this._loading = false;
}}
} Sample SdkUseCaseWidget.html
The Apex controller that the LWC uses calls the Data Query SDK.
SF_Archive.ArchiverAccessor.performArchiverGlobalSearch(sObjectName, request, fields, range);This is the call for the Archive SDK. It includes these parameters.
- sObjectName—Depicts the Search
- Filters—Used to retrieve the data
- Fields—The projected fields to return from data.
- Range—The date range used to query the data.
<template>
<template if:true={_loading}>
<lightning-spinner></lightning-spinner>
</template>
<lightning-datatable
key-field="caseNumber"
data={records}
columns={columns}
hide-checkbox-column>
</lightning-datatable>
</template>ArchiveSdk.cls
This code block is the Apex controller.
public with sharing class ArchiveSDK {
@AuraEnabled
public static List<CaseTableWrapperExample.CaseRecord> getCases(String parentId) {
// Create an empty list to hold maps with String keys and Object values
List<Map<String, Object>> totalRecords = new List<Map<String, Object>>();
// Create a list to store search filter objects
List<SF_Archive.SearchFilter> request = new List<SF_Archive.SearchFilter>();
// Create a search filter for the 'AccountId' field with a given 'parentId' value
SF_Archive.SearchFilter filter1 = new SF_Archive.SearchFilter('AccountId', parentId);
// Create a search filter for the 'Priority' field with a given 'High' value
SF_Archive.SearchFilter filter2 = new SF_Archive.SearchFilter('Priority', 'High');
// Add the filters to the request list
request.add(filter1);
request.add(filter2);
// Define the object name as 'Case'
String sObjectName = 'Case';
// Create a list of Strings representing field names to be retrieved from Archive DB
List<String> fields = new List<String>{'CaseNumber', 'Subject', 'Priority', 'Status'};
// Create the DateRange based on the created date
SF_Archive.DateRange range = new SF_Archive.DateRange('CreatedDate', system.today() - 150, system.today());
// Perform an initial global search and store the response
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch(sObjectName, request, range);
// Check if the HTTP response status code is 200 (success)
if (res.getStatusCode() == 200) {
system.debug('code: ' + res.getStatuscode());
// Retrieve the initial search response map
SF_Archive.ArchiverAccessorSearchResponse searchResponse = res.getSearchResponseMap();
system.debug('count: ' + searchResponse.totalResultCount);
system.debug('scrollid: ' + searchResponse.scrollId);
system.debug('list size: ' + searchResponse.records.size());
// Store the scroll ID for pagination
String scrollId = searchResponse.scrollId;
// Initialize the page number
Integer page = 1;
// Add the records from the initial search to the totalRecords list
totalRecords.addAll(searchResponse.records);
// Continue to fetch additional pages while the scroll ID is not '-1'
while (scrollId != '-1') {
page++;
// Get the next page of search results using the UPDATED scrollId
SF_Archive.ArchiverAccessorResponse nextPageResponse = SF_Archive.ArchiverAccessor.getNextPage(scrollId);
// Check if the HTTP response status code is 200 (success)
if (nextPageResponse.getStatusCode() == 200) {
// Retrieve the search response for the current page
SF_Archive.ArchiverAccessorSearchResponse searchResponse2 = nextPageResponse.getSearchResponseMap();
// CRITICAL FIX: Update the scrollId with the value from the new response
scrollId = searchResponse2.scrollId;
system.debug('count: ' + searchResponse2.totalResultCount);
system.debug('scrollid: ' + searchResponse2.scrollId);
system.debug('list size: ' + searchResponse2.records.size());
system.debug('page number: ' + page);
// Add the records from the current page to the totalRecords list
totalRecords.addAll(searchResponse2.records);
} else {
// Output an error message if the HTTP response status code is not 200
system.debug('response is != 200: ' + nextPageResponse.getStatusCode());
system.debug('body: ' + nextPageResponse.getBody());
// Break out of the loop if there is an error
break;
}
} // End of while loop
} else {
// Handle error from initial search
system.debug('status code error: ' + res.getStatusCode());
system.debug('status code message: ' + res.getErrorMessage());
}
// Return the list of total records
List<CaseTableWrapperExample.CaseRecord> result = new List<CaseTableWrapperExample.CaseRecord>();
return CaseTableWrapperExample.getCasesTable(totalRecords);
}
}CaseTableWrapperExample.cls
Helper class to formulate class from Apex to LWC
public class CaseTableWrapperExample{
public static List<caseRecord> getCasesTable(list<map<string,object>> cases){
List<caseRecord> caseReturnList = new List<caseRecord>();
for(Map<string,object> caseRecord: cases){
caseRecord tempCase = new caseRecord();
tempCase.caseNumber = String.valueOf(caseRecord.get('CaseNumber'));
tempCase.id = String.valueOf(caseRecord.get('Id'));
tempCase.origin = String.valueOf(caseRecord.get('Origin'));
tempCase.status = String.valueOf(caseRecord.get('Status'));
tempCase.subject = String.valueOf(caseRecord.get('Subject'));
tempCase.priority = String.valueOf(caseRecord.get('Priority'));
caseReturnList.add(tempCase);
}
return caseReturnList;
}
public class caseRecord {
@AuraEnabled public string caseNumber;
@AuraEnabled public string id;
@AuraEnabled public string origin;
@AuraEnabled public string status;
@AuraEnabled public string priority;
@AuraEnabled public string subject;
}}The above code describes a sample scenario whereby you can add LWC as a widget to the Lightning page.
To view the actual Lightning data table, add this code to the
sampleSdkUseCaseWidget.js-meta.xml file. Then add the Archive
Widget to the Lightning Page.
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="<a href='http://soap.sforce.com/2006/04/metadata">;
<apiVersion>55.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<supportedFormFactors>
<supportedFormFactor type="Small" />
<supportedFormFactor type="Large" />
</supportedFormFactors>
</targetConfig>
<targetConfig targets="lightning__AppPage">
<supportedFormFactors>
<supportedFormFactor type="Small" />
<supportedFormFactor type="Large" />
</supportedFormFactors>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>Archive SDK Data Query—Sample Use Case 2
This example use case shows how Archive SDK handles tasks without exceeding governor limits, such as CPU limits or Timeout callouts, in the Archive app.
For more information, see Apex Governor Limits.
Use Case
Your business requires that the Tier 3 Support Team has access to view archived Cases with a high-priority status.
This example shows how to work around an error when the number of archived records
retrieved via the SDK is too large. The error reads:
SF_Archive.ArchiverAccessor.ArchiverAccessorException: Exceeded time
allotted for callout, please contact support.
Code from these Apex classes creates this use case.
The ArchiveSecondPageJob class processes paginated data from Archive
by using a scroll ID, making callouts as needed. It runs asynchronously via the
Queueable interface, tracking the total execution time to avoid exceeding limits and
enqueuing itself for continued processing if necessary. The class handles responses,
updates the scroll ID, and logs details about each retrieved data page.
public class ArchiveSecondPageJob implements Queueable,Database.AllowsCallouts {
private String scrollId;
private long totalTime;
private integer pageNumber;
public archiveSecondPageJob(String prevScrollId, integer pageNumber) {
scrollId = prevScrollId;
this.pageNumber = pageNumber;
}
public void execute(QueueableContext context) {
system.debug('executing');
doExecute();
}
private void doExecute() {
SF_Archive.ArchiverAccessorSearchResponse searchResponse = null;
integer page = 1;
long totalTime = 0;
while(scrollId != '-1')
{
//avoid 12000 ms limit
if(totalTime > 90000){
system.debug('Creating new task');
archiveSecondPageJob q = new archiveSecondPageJob(scrollId,this.pageNumber);
System.enqueueJob(q);
return;
}
//Get the next page using the scrollId
Long startTime = DateTime.now().getTime();
SF_Archive.ArchiverAccessorResponse nextPage = SF_Archive.ArchiverAccessor.getNextPage(scrollId);
Long stopTime = DateTime.now().getTime();
totalTime += stopTime - startTime;
if(nextPage.getStatusCode() == 200){
this.pageNumber++;
SF_Archive.ArchiverAccessorSearchResponse searchResponse2 =nextPage.getSearchResponseMap();
scrollId = searchResponse2.scrollId;
system.debug('count: '+ searchResponse2.totalResultCount);
system.debug('scrollid: '+ searchResponse2.scrollId);
system.debug('list size: '+ searchResponse2.records.size());
system.debug('body: '+ searchResponse2.records);
system.debug('page: '+ pageNumber);
system.debug('time: '+ totalTime);
}
else{
system.debug('response is != 200: '+ nextPage.getStatusCode());
system.debug('body: '+ nextPage.getBody());
return;
}
}
}
}
The ArchiveSearch class performs a search on the Case object by
using specific filters, retrieves the results, and logs details such as the total
count and scroll ID. If the search returns a valid scroll ID, indicating more pages
of results, it enqueues the archiveSecondPageJob to process the
next page asynchronously. This class essentially initiates the search and hands off
further processing to the previously defined
archiveSecondPageJob.
Here's the format for the initial search call.
public class ArchiveSearch {
public void doSearch(){
string sObjectName = 'Case';
list<SF_Archive.SearchFilter> request = new list<SF_Archive.SearchFilter>();
SF_Archive.SearchFilter filter1 = new SF_Archive.SearchFilter('Priority', 'High');
request.add(filter1);
list<string> fields = new list<string>{'CaseNumber', 'Id'};
SF_Archive.ArchiverAccessorResponse res = SF_Archive.ArchiverAccessor.performArchiverGlobalSearch(sObjectName, request, fields);
if(res.getStatusCode() == 200){
system.debug('code: ' + res.getStatuscode());
SF_Archive.ArchiverAccessorSearchResponse searchResponse = res.getSearchResponseMap();
system.debug('count: '+ searchResponse.totalResultCount);
system.debug('scrollid: '+ searchResponse.scrollId);
system.debug('list size: '+ searchResponse.records.size());
string scrollId = searchResponse.scrollId;
integer page = 1;
if(scrollId != '-1'){
system.debug('calling next page');
integer pageNumber = 2;
archiveSecondPageJob q = new archiveSecondPageJob(scrollId, pageNumber);
System.enqueueJob(q);
}}}}For more information, see Salesforce Apex Developer Guide.

