Reputation: 61
I have a use case where I want to send a notification every time triples are added or deleted from MarkLogic. The notification should contain those triples and should say whether they were added or deleted.
I didn't find any mention in the MarkLogic triggers guide regarding how it might work with (managed) triples. Is there a way to write a trigger module so that for a modified document (containing the managed triples), compare the new version with the old version to work out what's added and deleted and send a HTTP request containing these changes?
I understand that doc($trgr:uri) will give me the latest state of the document in question - but is there a way to retrieve the previous version, before the change? I'm fairly new to MarkLogic and Xquery so some guidance is much appreciated. Thanks!
Upvotes: 4
Views: 117
Reputation: 61
Many thanks to @grtjn for providing the way to access the pre-change document. For determining the difference between documents I found a way inspired by this blog post. The solution that I found to be working looks like this:
xquery version '1.0-ml';
import module namespace trgr='http://marklogic.com/xdmp/triggers' at '/MarkLogic/triggers.xqy';
declare function local:diff($seq1 as item()*, $seq2 as item()*) as item()* {
let $map1 := map:new($seq1 ! map:entry(fn:string(.), .))
let $map2 := map:new($seq2 ! map:entry(fn:string(.), .))
return map:keys($map1 - $map2) ! map:get($map1,.)
};
declare variable $trgr:uri as xs:string external;
declare variable $after := doc($trgr:uri)/sem:triples/sem:triple;
declare variable $before := xdmp:eval('doc("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)/sem:triples/sem:triple;
declare variable $added_triples := local:diff($after, $before);
declare variable $added_graph := xdmp:document-get-collections($trgr:uri);
declare variable $deleted_triples := local:diff($before, $after);
declare variable $deleted_graph := xdmp:eval('xdmp:document-get-collections("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>);
xdmp:log(fn:concat('***** Trigger processing: ', $trgr:uri, '*****')),
xdmp:log('***** added triples *****'),
xdmp:log($added_graph),
xdmp:log($added_triples),
xdmp:log('***** deleted triples *****'),
xdmp:log($deleted_graph),
xdmp:log($deleted_triples)
I created 3 pre-commit
triggers, one for each of the trgr:document-content
options: create
, modify
and delete
, all invoking the above module. A SPARQL Update query will cause the above module to trigger one or more times, printing the lists of triples which were added and deleted.
Couple of observations:
Upvotes: 2
Reputation: 20414
I think you can only achieve this in one way:
pre-commit
triggersxdmp:eval
with isolation
for different-transaction
to get the original documentSomething like:
xquery version "1.0-ml";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
declare variable $trgr:uri as xs:string external;
xdmp:log("Triggered processing of " || $trgr:uri || ".."),
xdmp:log(xdmp:eval('doc("'||$trgr:uri||'")', (), <options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)),
xdmp:log(doc($trgr:uri))
I ran a quick test with a trigger scoped for collection 'test'. I then inserted a doc at /test.xml with contents <test>a</test>
, and did NOT add it to collection test yet. I then updated the document with <test>b</test>
, and also added it to collection test to activate the trigger. It logged a and b..
This shows how you can get both original and updated document. Determining the difference is a challenge on its own..
HTH!
Upvotes: 2