2016-03-01 13 views
8

Ho un codice che esercita il “invalid values” setting on an element range index. In questo caso, ho configurato un indice di intervallo di elementi dateTime sull'elementonel mio database (che si applicherà sia agli elementi XML che alle proprietà JSON). Ho impostato quell'indice per rifiutare valori non validi. Questa impostazione significa che se provo a impostare il valore di un elemento onDate e non è calcolabile a dateTime o è nullo (letteralmente null in JSON o xsi:nil="true" in XML), il mio aggiornamento non riuscirà. (Il comportamento opposto è quello di ignorare completamente i valori non validi.)Perché non riesco a rilevare alcune eccezioni in una richiesta MarkLogic?

ho provato il seguente codice nel lato server JavaScript Mark Logic 8,0-4:

'use strict'; 
declareUpdate(); 
var errors = []; 
var inputs = { 
'/37107-valid.json': (new Date()).toISOString(), 
'/37107-invalid.json': 'asdf', // Should throw an error 
'/37107-null.json': null 
}; 

for(var uri in inputs) { 
try { 
    xdmp.documentInsert(
    uri, 
    { 'onDate': inputs[uri] }, 
    xdmp.defaultPermissions(), 
    ['37107'] // Collections 
    ); 
} catch(err) { 
    errors.push(err); 
} 
} 
errors.length; 

mi sarei aspettato la mia richiesta per avere successo e alla fine con 1 === errors.length, perché solo il secondo inserimento avrebbe avuto esito negativo poiché 'asdf' non è utilizzabile come dateTime e non è nullo. Tuttavia, invece, ottengo un errore XDMP-RANGEINDEX e la mia transazione fallisce. Perché il mio try/catch non funziona qui?

risposta

13

Il problema è come i processi di MarkLogic aggiornano le transazioni. Invece di modificare effettivamente i dati con ciascuna chiamata xdmp.docuentInsert(…), MarkLogic mette in coda tutti gli aggiornamenti e li applica atomicamente alla fine della richiesta. (Questo è anche il motivo per cui non è possibile visualizzare gli aggiornamenti del database all'interno della stessa transazione.) Pertanto, l'errore non viene generato fino a quando il ciclo non viene eseguito e il database tenta di eseguire il commit delle transazioni in coda. Questo comportamento è lo stesso in XQuery (leggermente semplificata):

let $uris := (
'/37107-valid.xml', 
'/37107-invalid.xml', 
'/37107-null.xml' 
) 
let $docs := (
<onDate>{fn:current-dateTime()}</onDate>, 
<onDate>asdf</onDate>, 
<onDate xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
) 
return 
for $uri at $i in $uris 
return 
    try { 
    xdmp:document-insert($uri, $docs[$i],(), ('37107')) 
    } catch($err) { 
    xdmp:log($err) 
    } 

Per raggiungere gli errori in modo sincrono, avresti bisogno di mettere ogni aggiornamento nella propria transazione. In generale, questo approccio sarà molto più lento e dispendioso in termini di risorse rispetto alla gestione predefinita delle transazioni di MarkLogic. Tuttavia, è illustrativo qui per dimostrare cosa sta succedendo sotto le copertine e può tornare utile per casi d'uso specifici, come questo.

Nell'esempio seguente, utilizzo xdmp.invokeFunction() per "chiamare" una funzione in una transazione separata dalla richiesta padre. (Funzioni di prima classe per la vittoria!) Ciò consente agli aggiornamenti di essere completamente applicati (o ripristinati con un errore) e al modulo di chiamata di vedere gli aggiornamenti (o errori). Ho spostato il livello basso xdmp.invokeFunction() nella mia funzione applyAs() per fornire alcune sottigliezze, come passare correttamente gli argomenti della funzione alla funzione al curry.

'use strict'; 

var errors = []; 
var inputs = { 
'/37107-valid.json': (new Date()).toISOString(), 
'/37107-invalid.json': 'asdf', 
'/37107-null.json': null 
}; 

var insert = applyAs(
function(uri, value) { 
    return xdmp.documentInsert(
    uri, 
    { 'onDate': inputs[uri] }, 
    xdmp.defaultPermissions(), 
    ['37107'] 
    ); 
}, 
{ isolation: 'different-transaction', transactionMode: 'update' }, 
'one' 
); 

for(var uri in inputs) { 
try { 
    insert(uri, inputs[uri]); 
} catch(err) { 
    errors.push(err); 
} 
} 
errors.length; // Correctly returns 1 


// <https://gist.github.com/jmakeig/0a331823ad9a458167f6> 
function applyAs(fct, options, returnType /* 'many', 'one', 'iterable' (default) */) { 
    options = options || {}; 
    return function() { 
    var params = Array.prototype.slice.call(arguments); 
    // Curry the function to include the params by closure. 
    // xdmp.invokeFunction requires that invoked functions have 
    // an arity of zero. 
    var f = (function() { 
     return fct.apply(null, params); 
    }).bind(this); 
    // Allow passing in user name, rather than id 
    if(options.user) { options.userId = xdmp.user(options.user); delete options.user; } 
    // Allow the functions themselves to declare their transaction mode 
    if(fct.transactionMode && !(options.transactionMode)) { options.transactionMode = fct.transactionMode; } 
    var result = xdmp.invokeFunction(f, options); // xdmp.invokeFunction returns a ValueIterator 
    switch(returnType) { 
     case 'one': 
     // return fn.head(result); // 8.0-5 
     return result.next().value; 
     case 'many': 
     return result.toArray(); 
     case 'iterable': 
     default: 
     return result; 
    } 
    } 
} 
+0

Ora è necessario accettare la tua risposta;) – joemfb

+0

immagino per evitare brogli elettorali, non potete accettare la propria risposta per due giorni. –

Problemi correlati