Search code examples
xquerymarklogic

Copy documents from one database to another in MarkLogic - xdmp:document-insert Failing


I am using the below code to copy documents from one database to another database in MarkLogic. But I am getting error - arg2 is not of type node() The xquery I am trying -

xquery version "1.0-ml";
for $doc in cts:search(doc(), cts:collection-query('Shipment'))
let $docuri := $doc/base-uri()
let $collections := xdmp:document-get-collections($docuri)
let $permissions := xdmp:document-get-permissions($docuri)
let $db-name := "GTM2_FINAL"
return
 xdmp:invoke-function(function()
  {
  xdmp:document-insert
  (
  $docuri, $docuri,
  <options xmlns="xdmp:document-insert" xmlns1="xdmp:eval">  
      <permissions>{xdmp:default-permissions()}</permissions>
      <collections>
           {
       <collection>GTM2_Shipment</collection>,
       <collection>Shipment</collection>
           }
        </collections>
      <database>{ xdmp:database("GTM2_TEST") }</database>
      <commit>auto</commit>
    </options>
    )
    }
    );

Here is the error I am getting -

[1.0-ml] XDMP-ARGTYPE: (err:XPTY0004) xdmp:document-insert(xs:anyURI("/shipment/test..."), xs:anyURI("/shipment/test..."), <options xmlns1="xdmp:eval" xmlns="xdmp:document-insert"><permissions>...</permissions>...</options>) -- arg2 is not of type node()

Solution

  • A couple of issues with your code, but the first one and what the error message is telling you, is that the second parameter for xdmp:document-insert() is not a node. You specified $docuri, which is a string value of the URI of the document. The second parameter should instead be $doc.

    The other issue I see is that you have mixed the parameters for the xdmp:document-insert() function with the options parameter for the xdmp:invoke-function(). Two different options params need to be specified, and the elements are bound to two different namespaces.

    The options parameter for the xdmp:document-insert() should be:

    <options xmlns="xdmp:document-insert">  
        <permissions>{xdmp:default-permissions()}</permissions>
        <collections>
          <collection>GTM2_Shipment</collection>
          <collection>Shipment</collection>
        </collections> 
    </options>
    

    Or if you want to use the permissions and collections of the document:

    <options xmlns="xdmp:document-insert">  
        <permissions>{$permissions}</permissions>
      <collections>{$collections}</collections> 
    </options>
    

    The options parameter for the xdmp:invoke-function() are:

    <options xmlns="xdmp:eval">
      <database>{ xdmp:database("GTM2_TEST") }</database>
      <commit>auto</commit>
    </options>
    

    And if you don't want to use the collections or permissions from the document, then no need to fetch them. The answer that I provided in previous answers showed a way to use them with the older API for xdmp:document-insert() that used collections and permissions as specific parameters, rather than within the options parameter.

    You let a variable $db-name with the value "GTM2_FINAL", but don't use it and instead have hard-coded the value in the eval option. Either use the variable instead of the string, or get rid of the unused variable.

    Applying the changes:

    xquery version "1.0-ml";
    for $doc in cts:search(doc(), cts:collection-query('Shipment'))
    let $docuri := $doc/base-uri()
    let $collections := xdmp:document-get-collections($docuri)
    let $permissions := xdmp:document-get-permissions($docuri)
    let $db-name := "GTM2_FINAL"
    return
     xdmp:invoke-function(function()
      {
        xdmp:document-insert(
          $docuri, $doc,
          <options xmlns="xdmp:document-insert">  
            <permissions>{$permissions}</permissions>
            <collections>{$collections}</collections> 
          </options>
        )
       },
       <options xmlns="xdmp:eval">
          <database>{ xdmp:database($db-name) }</database>
          <commit>auto</commit>
       </options>
     );
    

    If it makes it easier, you could also let named variables for the options, to make it easier to read and keep the actual function calls shorter:

    xquery version "1.0-ml";
    for $doc in cts:search(doc(), cts:collection-query('Shipment'))
    let $docuri := $doc/base-uri()
    let $collections := xdmp:document-get-collections($docuri)
    let $permissions := xdmp:document-get-permissions($docuri)
    let $document-insert-options := 
      <options xmlns="xdmp:document-insert">  
        <permissions>{$permissions}</permissions>
        <collections>{$collections}</collections> 
      </options>
    let $db-name := "GTM2_FINAL"  
    let $invoke-function-options := 
      <options xmlns="xdmp:eval">
        <database>{ xdmp:database($db-name) }</database>
        <commit>auto</commit>
      </options>
    return
     xdmp:invoke-function(
       function(){ xdmp:document-insert($docuri, $doc, $document-insert-options)},
       $invoke-function-options
     );