Multiple queryTask operations with maxRecordCount

1041
3
10-01-2018 11:46 AM
BlakeTerhune
MVP Regular Contributor

I tried searching but was surprised to not find any good results. Does anyone have a coding pattern to handle "paging" through a large query that exceeds the service's maxRecordCount property? I'd like to find a way to query the record count first, then build a bunch of query tasks with varying start and num properties to retrieve all the results. Promise.all() seems like it'd be what's needed but I can't quite wrap my head around how to make it all work. Here's my related question regarding distinct values that started this.

0 Kudos
3 Replies
RobertScheitlin__GISP
MVP Emeritus

Blake,

  Here is how I do that:

var iMaxRecords = 0;
var featuresProcessed = 0;
var featuresTotal = 0;
var maxRecordCount = layer.maxRecordCount; //normally 1000

queryTask = new QueryTask(uri);
var cntQuery = new Query();
cntQuery.where = "1=1";
queryTask.executeForCount(cntQuery, function(count){
  featuresTotal = count;
  if(count <= maxRecordCount){
    //not an issue where you need to page
  }else{
    query.returnGeometry = false;
    query.objectIds = null;
    query.where = "1=1";
    queryTask.executeForIds(query, onSearchIdsFinish, onSearchError);
  }
});

function onSearchIdsFinish(results){
  if (results.length > 0) {
    objectIdsArray = results;
    featuresTotal = objectIdsArray.length;
    query.where = null;
    query.text = null;
    query.objectIds = objectIdsArray.slice(0, maxRecordCount);
    queryTask.execute(query, onSearchFinish, onSearchError);
  } else {
    console.error('onSearchIdsFinish returned zero length');
    isQuerying = false;
    esc = false;
  }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

function onSearchFinish(featureSet) {
// do something with the results
  featuresProcessed += featureSet.features.length;

  if (iMaxRecords === 0) {
    iMaxRecords = featuresProcessed;
    iStart += iMaxRecords;
  }
  if (iStart < objectIdsArray.length) {
            //If we get this far we need to requery the server for the next lot of records
    query.objectIds = objectIdsArray.slice(iStart, iStart + iMaxRecords);
    queryTask.execute(query, onSearchFinish, onSearchError);

    iStart += iMaxRecords;
  }
}
BlakeTerhune
MVP Regular Contributor

Interesting approach, thanks. My feature layer (hosted at 10.5.1) doesn't have a maxRecordCount property. It doesn't even have a capabilities property. Any thoughts on that?

After posting I got something that I think works. Besides the fact it doesn't work with returnDistinctValues (as I mentioned before), I'm not sure how I feel about it.

var maxRecordCount = 1000;
var queryTask = new QueryTask();
queryTask.url = 'http://server/arcgis/rest/services/ServiceName/MapServer/0';
var queryParams = new Query({
  returnGeometry: false,
  outFields: ['someFieldName'],
  where: 'someFieldName is not null',
});
queryTask.executeForCount(queryParams)
.then(function(queryRecordCount) {
  var pageCount = Math.ceil(queryRecordCount / maxRecordCount);
  var resultPages = [];
  for (var i = 0; i < pageCount; i++) {
    resultPages.push(i * maxRecordCount);
  }
  return Promise.all(resultPages.map(function(resultPageStart){
    queryParams.start = resultPageStart;
    queryParams.num = maxRecordCount - 1;
    return queryTask.execute(queryParams);
  }))
})
.then(function(featureSets) {
  // collect features from each FeatureSet
  var features = [];
  featureSets.forEach(function(featureSet) {
    features = features.concat(featureSet.features);
  })
  // do something with array of features
})
.catch(function(err) {
  console.error(err);
});‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Blake,

  You can use QueryTask.exectueForCount() and in the Query object you can use returnDistinct. This will allow you to get a number that is in fact the real distinct count for your query. You then can decide if you need to use the paging route. Also the query result returns a exceededTransferLimit property that tells you if your results are not all the distinct data.

0 Kudos