2
votes

Suitecript 2.0 ResultSet Chaque fonction de rappel a dépassé 4000

J'ai écrit un script (ci-dessous) il y a quelques années (je n'ai pas codé depuis - donc il y en a pas mal ou rouille; D) où le ResultSet dépasse maintenant 4000 enregistrements, ce qui n'était pas prévu lorsque le script a été écrit. L'erreur est ci-dessous:

{"type": "error.SuiteScriptError", "name": "SSS_SEARCH_FOR_EACH_LIMIT_EXCEEDED", "message": "Pas plus de 4000 résultats de recherche peuvent être renvoyés à la fois à partir de nlobjSearchResultSet.forEachResult (rappel). Veuillez réviser votre critères de recherche ou modifiez la logique de rappel de sorte que pas plus de 4000 résultats ne soient renvoyés. "...

Est-ce que le meilleur moyen de résoudre ce problème est d'utiliser une technique différente (comme Map / Réduire - que je devrais apprendre maintenant), ou y a-t-il un moyen de filtrer la recherche afin que seulement un certain nombre de les résultats sont renvoyés par la recherche et le reste des enregistrements est renvoyé / traité lors d'une exécution ultérieure?

Merci

//...
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);
    }
});
//....


0 commentaires

3 Réponses :


2
votes

Ma recommandation et peut-être la meilleure pratique pour le traitement en masse dans SuiteScript 2.0 est d'utiliser un Map / Reduce plutôt qu'un script planifié. Il y a certainement une courbe d'apprentissage avec eux, mais ils sont extrêmement puissants.

Voici quelques conseils rapides:

  1. Votre point d'entrée getInputData peut simplement créer / charger ce que factureSearch se trouve dans le script existant et le renvoyer
  2. Vous pourrez vous débarrasser de toute la surveillance de l'utilisation car vous n'avez pas besoin de le faire vous-même avec un H / R
  3. Votre point d'entrée reduction sera en fait les entrailles de l'instruction if que vous avez là.

Il devrait s'agir d'une conversion assez simple, espérons-le.


0 commentaires

3
votes

Bien que la réponse d'Eric soit la façon dont je procéderais probablement, un script programmé est parfois la chose à faire. Et certainement dans ce cas, si vous pensez que vous travailleriez sur tous les éléments en une journée d'exécutions planifiées, une solution simple est:

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 commentaires

4
votes

Personnellement, j'aime générer la recherche complète, puis l'analyser à partir de là:

J'utilise cette fonction avec n'importe quel objet de recherche pour compiler les résultats par blocs de 1000:

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

});

Ensuite, lorsque je souhaite traiter une recherche, par exemple:

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;
}   

Je l'ai utilisé avec de bons résultats sur des ensembles de données de plus de 20 000 enregistrements. p >


0 commentaires