Das Problem ist, wie MarkLogic Update-Transaktionen verarbeitet. Anstatt die Daten tatsächlich mit jedem xdmp.docuentInsert(…)
Aufruf zu ändern, reiht MarkLogic alle Aktualisierungen ein und wendet sie am Ende der Anforderung atomar an. (Dies ist auch der Grund, warum Datenbankaktualisierungen nicht innerhalb derselben Transaktion angezeigt werden können.) Daher wird der Fehler erst nach der Ausführung der Schleife ausgelöst, und die Datenbank versucht, die eingereihten Transaktionen zu übernehmen. Dieses Verhalten ist das gleiche in XQuery (etwas vereinfacht):
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)
}
Um synchron um die Fehler zu fangen, würden Sie jedes Update in seine eigene Transaktion setzen müssen. Im Allgemeinen ist dieser Ansatz wesentlich langsamer und ressourcenintensiver als die Standard-Transaktionsverarbeitung von MarkLogic. Es ist jedoch illustrativ, um zu demonstrieren, was unter den Abdeckungen passiert, und kann für bestimmte Anwendungsfälle wie diese nützlich sein.
Im folgenden Beispiel verwende ich xdmp.invokeFunction()
, um eine Funktion in einer separaten Transaktion von der übergeordneten Anforderung "aufzurufen". (Erstklassige Funktionen für den Gewinn!) Dadurch können die Updates vollständig angewendet (oder mit einem Fehler zurückgesetzt) und das aufrufende Modul die Updates (oder Fehler) sehen. Ich habe die Low-Level-xdmp.invokeFunction()
in meiner eigenen applyAs()
-Funktion, um einige Feinheiten, wie korrekt übergeben Funktionsargumente an die Curry-Funktion.
'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;
}
}
}
Jetzt müssen Sie Ihre Antwort akzeptieren;) – joemfb
Ich stelle mir vor Stimmzettel Füllung zu vermeiden, können Sie Ihre eigene Antwort für zwei Tage nicht akzeptieren. –