2

I am trying to replace around 500 Nodes in a single go for a single document and i am having 5000+ document in my database.

The code which i am using is related to this SO question i asked previously- Link

Any suggestions to make my code efficient ?

1 Answer 1

5

The in-mem-update library should generally be avoided, especially when making numerous method calls for the same document. Since each method walks the entire node tree and generates a brand new document, it can be slow and expensive if you run against large documents and/or make a bunch of mem:* method calls on those docs.

A better replacement would be Ryan Dew's XQuery XML Memory Operations library, or to use XSLT.

Below is an example of how you could perform this sort of "merge" with XSLT that should perform way better than the in-mem-update methods:

declare variable $STAGING := document{
<root>
 <ID>1</ID>
 <value1>India</value1>
 <value2>USA</value2>
 <value3>Russia</value3>
 <value4>Srilanka</value4>
 <value5>Europe</value5>
 <value6>Antartica</value6>
 <value7>Spain</value7>
</root>
};

declare variable $FINAL := document{
<root>
 <ID>1</ID>
 <value1></value1>
 <value2></value2>
 <value3></value3>
 <value4></value4>
 <value5>Europe</value5>
 <value6>Antartica</value6>
</root>
};

declare variable $XSLT := 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

  <xsl:param name="staging-doc"/>
  <xsl:param name="element-names"/>

  <xsl:variable name="final-doc" select="/"/>

  <xsl:key name="staging-elements" match="root/*[local-name() = $element-names]" use="local-name()"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="root/*[local-name() = $element-names]">
    <!--if there is an element in the staging-elements doc with this name, use it. Otherwise, use the matched element from this doc -->
    <xsl:copy-of select="(key('staging-elements', local-name(.), $staging-doc), .)[1]"/>
  </xsl:template>

  <xsl:template match="root">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <!-- also copy any other elements with the specified names from the staging document that were not already in the final -->
      <xsl:apply-templates select="$staging-doc/root/*[local-name() = $element-names and not(key('staging-elements', local-name(), $final-doc))]"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>;

declare variable $PARAMS := map:new((
    map:entry("staging-doc", $STAGING), 
    map:entry("element-names", tokenize(("value1,value2,value3,value4,value7"), ",") )
  ));

xdmp:xslt-eval($XSLT, $FINAL, $PARAMS)
Sign up to request clarification or add additional context in comments.

3 Comments

@Mads-- Thank you so much. Will it require xdmp:document-insert () as well ? or it will automatically replace all the documents into DB ?
Yes, you will need to save the result (use in the section of your code where you are conditionally setting $envelope inside of the if ($boolean) then, instead of using the in-mem functions)
@Mads-- Thank you so much :) That helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.