Suitescript 2.0 ResultSet.Each Функция обратного вызова превысила 4000 - PullRequest
0 голосов
/ 15 января 2019

Я написал сценарий (ниже) пару лет назад (с тех пор не кодировал - так что существует значительное количество или ржавчина; D), где ResultSet теперь превышает 4000 записей, что не ожидалось на момент написания сценария. Ошибка ниже:

{"type": "error.SuiteScriptError", "name": "SSS_SEARCH_FOR_EACH_LIMIT_EXCEEDED", "message": "Одновременно из nlobjSearchResultSet.forEachResult (callback) может быть возвращено не более 4000 результатов поиска. критерий поиска или измените логику обратного вызова, чтобы возвращалось не более 4000 результатов. "...

Это лучший способ исправить это, используя другую технику (например, Map / Reduce - которую я должен был бы изучить сейчас), или есть способ отфильтровать поиск, чтобы из определенного числа возвращалось только определенное количество результатов. поиск и остальные записи возвращаются / обрабатываются при последующем выполнении?

Спасибо

//...
invoiceSearch.run().each(function(result) {
    // ensure script usage okay
    if (usageOkay()) {
        entityID = result.getValue({
            'name': 'internalid',
            'join': 'customer',
            'summary': search.Summary.GROUP
        });

        var maxAmountCustomerRecord = result.getValue({
            'name': 'custentity_amount_maxorder_2years',
            'join': 'customer',
            'summary': search.Summary.GROUP
        });

        var maxAmountCalculated = result.getValue({
            'name': 'formulacurrency',
            'formula': 'CASE WHEN {closedate} >= ADD_MONTHS(SYSDATE, -(12 * 2)) THEN {amount} ELSE NULL END',
            'summary': search.Summary.MAX
        });
        // in case the calculated amount is null then make it 0
        maxAmountCalculated = maxAmountCalculated || 0.0;
        // Only write to the customer record when a change is required
        if (maxAmountCustomerRecord != maxAmountCalculated) {
            updateRecord(entityID, maxAmountCalculated);
            log.debug('Updating customer with entityID: ' + entityID + ', to maxAmount: ' +
                maxAmountCalculated + ', from previous value of ' + maxAmountCustomerRecord);
        }
        return true;
    }
    else {
        // If remaining script usage low, reschedule script
        rescheduleScript(entityID);
    }
});
//....

Ответы [ 3 ]

0 голосов
/ 15 января 2019

В то время как ответ Эрика - путь, по которому я, вероятно, иногда буду делать запланированный сценарий. И, конечно, в этом случае, если вы думаете, что будете работать со всеми пунктами в запланированных за день запусках, тогда простое исправление:

var count = 0;
invoiceSearch.run().each(function(result) {
   count++;
   if(count == 4000) return false;
   if(usageOk(){
     ...
     return true;
   }else{
     rescheduleScript(entityID);
      return false; // end the each and you may never hit 4k anyway
   }
});
0 голосов
/ 16 января 2019

Мне лично нравится генерировать полный поиск, а затем анализировать его оттуда:

Я использую эту функцию с любым объектом поиска, чтобы скомпилировать результаты в блоках по 1000:

function getAllResults(s) {
    var results = s.run();
    var searchResults = [];
    var searchid = 0;
    do {
        var resultslice = results.getRange({start:searchid,end:searchid+1000});
        resultslice.forEach(function(slice) {
            searchResults.push(slice);
            searchid++;
            }
        );
    } while (resultslice.length >=1000);
    return searchResults;
}   

Тогда, когда я хочу обработать любой поиск, например:

var mySearch = search.create({
                type:'invoice',
                columns: [
                    {name: 'tranid'},
                    {name: 'trandate'},
                    {name: 'entity', sort: (params.consolidated)?search.Sort.ASC:undefined },
                    {name: 'parent',join:'customer', sort: (!params.consolidated)?search.Sort.ASC:undefined},
                    {name: 'terms'},
                    {name: 'currency'},
                    {name: 'amount'},
                    {name: 'amountremaining'},
                    {name: 'fxamount'},
                    {name: 'fxamountremaining'},
                ],
                filters: [
                    {name: 'mainline', operator:'is',values:['T']},
                    {name: 'trandate', operator:'onorbefore', values: [params.startDate] }
                ]
            });

var myResults = getAllResults(mySearch );

myResults.forEach(function(result) {

//... do stuff with each result

});

Я использовал это с хорошими результатами для наборов данных, превышающих 20 000 записей.

0 голосов
/ 15 января 2019

Моя рекомендация и, возможно, лучший способ массовой обработки в SuiteScript 2.0 - использовать Map / Reduce, а не Scheduled Script. Конечно, с ними есть некоторая кривая обучения, но они чрезвычайно мощные.

Быстрые советы будут:

  1. Ваша getInputData точка входа может просто создать / загрузить все, что invoiceSearch находится в существующем скрипте, и вернуть его
  2. Вы сможете избавиться от всего мониторинга использования, поскольку вам не нужно делать это самостоятельно с помощью M / R
  3. Ваша точка входа reduce будет фактически основой вашего оператора if.

Надеемся, это должно быть довольно простым преобразованием.

...