To Update Parts of Document Content
[v11.2.0 and up]
You can update parts of document content such as changing a specific value or adding a new property. You can do this without needing to provide any of the other data or metadata that you are not updating.
We want to change the employee document Status
property from Active - Regular Exempt (Full-time)
to Terminated
for each employee terminated so far.
We also want to add a property: TerminationDate
.
An Optic update like this one finds all the documents in a collection then replaces one of the values and adds a new property and value to each document found:
declareUpdate(); const op = require('/MarkLogic/optic'); op.fromDocUris(cts.collectionQuery('https://example.com/content/department/Attrition')) .joinDocCols(null, op.fragmentIdCol('fragmentId')) .patch( op.col('doc'), op.patchBuilder('/') .replaceValue("Status", "Terminated") .insertAfter("HiredDate", xdmp.toJSON({"TerminationDate": fn.currentDate()}).root.TerminationDate) ) .write() .execute();
We used this update to replace the Status
value and add the TerminationDate
property--with the current date as its value--after the existing HiredDate
property in all documents in the Attrition collection:
The Data Accessor Function
fromDocUris()
produces a row for each document with the columnuri
containing the document URIs and the columnfragmentId
contaning the document root Fragment ID:The CTS Function
cts.collectionQuery()
matches documents in the specified collection, our Attrition collection.With this CTS function as a parameter,
fromDocUris()
produces a row for each matched document. Each row has auri
column containing the URIs for the documents that we want to update: the employee documents currently in the Attrition collection. Each row also has afragmentID
column containing the Fragment ID of each document.
The Operator Function
joinDocCols()
retrieves the actual document.null
tellsjoinDocCols()
to use default column names such asdoc
for document content.fragmentIdCol()
matches the value injoinDocCols()
'sfragmentId
column with the value infromDocUri()
'sfragmentId
column.
The Operator Function
patch()
applies the patch, once it is built, to the specified areas of each document in memory:col()
identifies the column in its argument.The Operator Function
patchBuilder()
defines a patch consisting of one or more patch builder plan functions:/
is an XPath expression that selects the root node of the document.The Patch Builder Plan Function
replaceValue()
defines the first change to be applied: Changing the employee status property to terminated:Status
is an XPath expression selecting the property to update.Terminated
is the new value for that property.
The Patch Builder Plan Function
insertAfter()
defines the second change to be applied: Adding an employee termination date property withfn.currentDate()
(today's date) determining its value:HiredDate
is an XPath expression identifying the sibling property after which to add the new property.xdmp.toJSON()
converts the new native JavaScript Object{ "Termination":"<current date>" }
into a MarkLogic DocumentObject..root.TerminationDate
accesses theTerminationDate
object node property to insert.
The Operator Function
write()
inserts each document, by default giving it the URI in theuri
column created by the latest data accessor function.The Executor Function
execute()
executes the update without returning any rows.Optic data accessor functions always pull the document root Fragment ID into a
fragmentId
column. However, operator functions do not process that column and executor functions do not produce that column as part of the result unless a preceding operator function explicitly defines that column.To test the update before writing the document, replace
write()
andexecute()
withresult()
to return the rows thatfromDocDescriptors()
has rendered.You cannot insert a child on an existing property whose value is
null
.You cannot add another attribute with the same name to an element.
You cannot add a JSON property of the same name under the same parent property.
A document cannot have more than one root. Therefore, you cannot insert a property before or after the root of a document.
You cannot add an XML element or attribute node to a JSON document nor a JSON property or array node to an XML document.
Each Patch Builder Function applies to all items matching the provided XPath expression:
If it matches more than one node in a document, then the patch applies to all instances.
If it matches no property in the document, no changes are applied.
The documents in the Attrition collection now have the old property Status
updated to Terminated
and the new property TerminationDate
containing today's date.
To return rows, use
result()
instead ofexecute()
.