Search code examples
marklogicmarklogic-9

In marklogic 9, how to make updates visible in the same transaction?


In marklogic 9, I have a resource service extension written in xquery. It is a 'delete' endpoint, so the transaction mode is 'update'. I do something similar to:

(: search for objects that have /a/id = $theId :)
let $objs := cts:search(fn:doc(), cts:path-range-query('/a/id', $theId)
(: log the number of results :)
let $_ := xdmp:log(fn:count($objs))

(: for each of the objects, remove the /a/id node :)
let $_ := for ($obj in $objs) xdmp:node-delete($obj/a/id)

(: search for objects that have /a/id = $theId :)
let $objs2 := cts:search(fn:doc(), cts:path-range-query('/a/id', $theId)
(: log the number of results :)
let $_ := xdmp:log(fn:count($objs2))

My first expectation was that the logged values would be different: the first one would be the number of results for the search and the second one would always be zero, since I removed the '/a/id' node from each of the results. But, both logged values are always the same. i.e. the changes done in the transaction are not visible in the extension.

I read in https://docs.marklogic.com/guide/app-dev/transactions#id_85012 that updates are not visible within the updating statement, so I tried to make the resource service extension to behave like a multi-statement update, without luck. I also tried to explicitly call let $_ := xdmp:commit() before doing the second search, again with no luck.

Is it possible to have the behavior I want in a xquery resource service extension?


Solution

  • MarkLogic is fully ACID so as you've correctly identified a document will not be updated in the database until the updating transaction completes. Thus, at the time you run the second cts:search call you won't yet see the updated document reflected in the results because your updating transaction has not yet finished.

    My recommendation is typically to steer people away from trying to boil the ocean in a single transaction or REST extension but rather break things up where it makes sense to. I'd recommend in your case making one REST Extension to count or otherwise read data and one REST extension to do your node deletion update. Most likely you could even use /v1/search in lieu of writing an extension to count documents.

    You could accomplish running multiple transactions in a single REST Extension if you leverage functions like xdmp:eval or xdmp:invoke to do so. However, I find it typically makes code harder to maintain and debug when designed this way. There can be performance drawbacks to using these functions unnecessarily as well.