This chapter discusses the following topics related to using the REST Client API to create, read, update and delete documents and metadata:
This section gives a brief summary of the REST Client API services available for creating, reading, updating, and delete documents. This section covers the following topics:
Use the /documents
service to create, read, update, and delete document content and metadata for XML, JSON, text, and binary documents, including XML documents containing embedded semantic RDF triple data. To load documents containing only RDF triples, use the /graph
service; for details, see Summary of the /graphs Service.
The following table summarizes the supported operations:
The service supports the following additional document features through request parameters:
XML, JSON and text documents must use UTF-8 encoding.
The service does not support content conversions except through custom transformations. For example, you cannot retrieve an XML document as JSON.
You can also use POST:/v1/documents/protection
to protect temporal documents from various levels of update. For details, see Working with Temporal Documents and the MarkLogic REST API Reference.
This chapter only covers single-document operations. For multi-document operations, see Reading and Writing Multiple Documents.
Use the /graphs
service to create, read, update, and delete documents containing RDF triples. For triples embedded in XML documents, use the /documents
service.
The following table summarizes the supported operations:
Though a graph can include both triples embedded in XML documents and triples from a pure triples document (one with a <sem:triples>
root element), the /graphs
service does not operate on embedded triples. For example, if you make a DELETE request on a graph that includes embedded triples, the embedded triples and their containing document are unaffected, and therefore, the graph continues to exist.
For details, see Loading Triples Using the REST API in Semantics Developer's Guide.
This section focuses on ingesting whole documents and their metadata into the database. To learn about modifying just a portion of a document, see Partially Updating Document Content or Metadata.
To insert content or metadata into the database, make a PUT or POST request to the /documents
service. This section covers the following topics:
This section describes how to insert or update an entire document at a user-defined database URI. If you want to have MarkLogic Server generate document URIs automatically, see Automatically Generating Document URIs. You can also modify only a portion of a document; for details, see Partially Updating Document Content or Metadata. For loading multiple documents in a single request, see Reading and Writing Multiple Documents.
To insert or update an XML, JSON, text, or binary document, make a PUT request to a URL of the form:
http://host:port/version/documents?uri=document_uri
When constructing the request:
uri
parameter to the URI of the destination document in the database.Content-type
HTTP header. The Content-type header does not necessarily determine the document type; for details, see Controlling Input and Output Content Type.XML, JSON and text documents must use UTF-8 encoding.
Whitespace is not allowed in REST URLs, but is allowed in older APIs for compatibility with older applications.
Documents you create with the REST Client API have a read permission for the rest-reade
r role and an update permission for the rest-writer
role. To restrict access, use custom roles. For details, see Controlling Access to Documents and Other Artifacts.
The following example command sends a request to insert the contents of the file ./my.xml
into the database as an XML document with URI /xml/example.xml
:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT -T ./my.xml \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/xml/example.xml
If the MIME type is not set in the HTTP Content-type header, MarkLogic Server uses the file extension on the document URI to determine the content format, based on the MIME type mappings defined for your installation. For details, see Controlling Input and Output Content Type.
You can also set metadata such as collections, permissions, and named properties when loading content. See Loading Content and Adding Metadata in the Same Request.
You can have MarkLogic Server generate document URIs for you. For details, see Automatically Generating Document URIs.
This section describes inserting or updating metadata using a PUT request to /documents
. The following topics are covered:
This section describes how to insert or update metadata independent of the document contents. To bundle content and metadata together, see Loading Content and Adding Metadata in the Same Request.
To insert or update only metadata for a document, make a PUT request to a URL of the form:
http://host:port/version/documents?uri=document_uri&category=metadata_category
Where category
can appear multiple times, with the values described in Metadata Categories.
You cannot supply metadata via request parameters when there is no document content. In this case, you must place the XML or JSON metadata in the request body.
When constructing the request:
category
parameter to the type of metadata to insert or replace. Specify category
multiple times to include more than one type of metadata.Content-type
header or the format
parameter. The Content-type
header generally take precedence; see below.If the Content-type
header MIME type is a MIME type that signifies XML or JSON, such as application/xml
or application/json
, then the Content-type header determines how MarkLogic interprets the request body. If the Content-type
header is absent or you cannot set it to a compatible MIME type, use the format
request parameter to specify the metadata format. For details, see Controlling Input and Output Content Type.
Metadata category merging is not available.
A PUT request for metadata completely replaces each category of metadata specified in the request. For example, a PUT request for collections replaces all existing collections.
When the category is metadata
, all metadata is replaced or reset to default values.
When setting permissions, at least one update permission must be included.
Any explicitly specified permissions are combined with the default permissions for the role of the current user.
Metadata for categories other than those named by the category
parameter(s) are ignored. For example, if the request body contains metadata for both collections and properties, but only category=collections
is given in the URL, then only the collections are updated.
The following example places the document with URI /xml/example.xml
into the interesting collection by specifying category=collections
. The document is removed from any other collections. The metadata XML in the request body defines the name of the collection(s).
$ cat metadata.xml <rapi:metadata xmlns:rapi="http://marklogic.com/rest-api" xmlns:prop="http://marklogic.com/xdmp/property"> <rapi:collections> <rapi:collection>interesting</rapi:collection> </rapi:collections> </rapi:metadata> # Windows users, see Modifying the Example Commands for Windows $ curl -X PUT -T ./metadata.xml -H "Content-type: application/xml" \ --anyauth --user user:password \ 'http://localhost:8000/LATEST/documents?uri=/xml/example.xml&category=collections'
This example replaces multiple types of metadata on the document with URI /xml/example.xml by specifying multiple category parameters. The metadata in the request body defines a collection name (interesting) and a property (my-property). The request URL includes category=collections
and category=properties
. Any collections or properties previously set for the document /xml/example.xml are replaced with the new values.
$ cat > metadata.xml <rapi:metadata xmlns:rapi="http://marklogic.com/rest-api" xmlns:prop="http://marklogic.com/xdmp/property"> <rapi:collections> <rapi:collection>interesting</rapi:collection> </rapi:collections> <prop:properties> <my-property>value</my-property> </prop:properties> </rapi:metadata> # Windows users, see Modifying the Example Commands for Windows $ curl -X PUT -T ./metadata.xml -H "Content-type: application/xml" \ --anyauth --user user:password \ 'http://localhost:8000/LATEST/documents?uri=/xml/example.xml&category=collections&category=properties'
This example replaces multiple types of metadata on the document with URI /xml/example.xml by specifying multiple category parameters. The JSON metadata in the request body defines a collection name (interesting) and a property (my-property). The request URL includes category=collections
and category=properties
. Any collections or properties previously set for the document /xml/example.xml are replaced with the new values.
$ cat > metadata.json { "collections":["interesting"], "properties": { "my-property":"name" } } # Windows users, see Modifying the Example Commands for Windows $ curl -X PUT -T ./metadata.json --anyauth --user user:password \ -H "Content-type: application/json" \ 'http://localhost:8000/LATEST/documents?uri=/xml/example.xml&category=collections&category=properties'
The example uses the Content-type header
to communicate the metadata content type to MarkLogic Server. The content type can also be specified using the format
request parameter; for details, see Controlling Input and Output Content Type.
You can update content and metadata for a document in a single request using the following methods. You must choose one or the other; they cannot be combined.
For loading multiple content and/or metadata for multiple documents in a single request, see Reading and Writing Multiple Documents.
Use this method when you want to specify metadata using request parameters. To load content and include metadata in the request parameters, send a PUT request of the following form to the/documents service:
http://host:port/version/documents?uri=doc_uri&metadata_param=value
Where metadata_param is one of collection
, perm:
role, prop:
name, quality
, or value:
key. For example, to set a document property named color to red, include prop:color=red
in the URL.
When constructing the request:
uri
parameter to the URI of the destination document in the database.Content-type
HTTP header.collection
or prop
.If the MIME type is not set in the Content-type header, MarkLogic Server uses the file extension on the document URI to determine the content format, based on the MIME type mapping defined for the database. MIME type mappings for file suffixes are defined in the Admin Interface. For details, see Controlling Input and Output Content Type.
The following example inserts a binary document with the URI /images/critter.jpg
into the database, adds it to the animals collection, and sets a species property:
# Windows users, see Modifying the Example Commands for Windows $ curl -X PUT -T ./critter.jpg --anyauth --user user:password \ -H "Content-type: image/jpeg" \ 'http://localhost:8000/LATEST/documents?uri=/images/critter.jpg&collection=animals&prop:species="canus lupus"'
Alternatively, you can pass JSON or XML metadata in the request body with the content. See Loading Content and Metadata Using a Multipart Message. You cannot combine the two methods.
Use this method when you want to insert or update both content and metadata for a document in a single request, and you want to specify the metadata as JSON or XML in the request body. You can also specify metadata using request parameters; for details, see Loading Content and Metadata Using Request Parameters. You cannot combine the two methods.
Construct a PUT request with a multipart/mixed
message body where the metadata is in the first part and the document content is in the second part of the request body. The request URL is of the form:
http://host:port/version/documents?uri=doc_uri&category=content&category=
metadata_category
Where category
can appear multiple times, with the values described in Metadata Categories.
When constructing the request:
uri
parameter to the URI of the destination document in the database.category=content
in the request URL to indicate content is included in the body.category
parameters to indicate the type(s) of metadata to add or update.multipart/mixed
in the HTTP Content-type header for the request.Content-type
of the first part to either application/xml
or application/json
and place the XML or JSON metadata in the part body.Content-type
of the second part to the MIME type of the content and place the content in the part body.For details on metadata formats, see Working with Metadata.
Metadata must always be the first part of the multipart body.
The following example inserts an XML document with the URI /xml/box.xml
into the database and adds it to the shapes and squares collection. The collection metadata is provided in XML format in the first part of the body, and the content is provided as XML in the second part.
$ cat ./the-body --BOUNDARY Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <metadata xmlns="http://marklogic.com/rest-api"> <collections> <collection>shapes</collection> <collection>squares</collection> </collections> </metadata> --BOUNDARY Content-Type: text/xml <?xml version="1.0" encoding="UTF-8"?> <data> <mybox> This is my box. There are many like it, but this one is mine. </mybox> </data> --BOUNDARY-- # Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT \ --data-binary @./the-body \ -H "Content-type: multipart/mixed; boundary=BOUNDARY" \ 'http://localhost:8000/LATEST/documents?uri=/xml/box.xml&category=collections&category=content'
MarkLogic Server can automatically generate database URIs for documents inserted with the REST API. You can only use this feature to create new documents. To update an existing document, you must know the URI; for details, see Loading Content.
To use this feature, send a POST request to /documents
that includes the extension
request parameter and does not include the uri
request parameter. That is, a POST request with a URL of the following form:
http://host:port/version/documents?extension=file-extension
Where extension specifies the document URI file prefix, such as xml
or txt
. Optionally, you can also include a database directory prefix with the directory
request parameter.
The directory prefix should end in a forward slash (/
).
MarkLogic Server returns the auto-generated URI in the Location header of the response.
The following example inserts a document into the database with a URI of the form /my/directory/
auto-generated.xml
:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X POST -d@'./my-content' -i \ -H "Content-type: application/xml" \ 'http://localhost:8000/LATEST/documents?extension=xml&directory=/my/directory/' HTTP/1.1 201 Document Created Location: /my/directory/6041706572796142832.xml ...
You can use the same features with generated URIs as when loading documents with user-defined URIs. For example, you can insert both documents and metadata and apply content transformations. For details, see Loading Content into the Database and the MarkLogic REST API Reference.
You can use the /graphs
service to load semantic triples into the database in several formats. The service implements the W3C Graph Store Protocol, described by the following specification:
http://www.w3.org/TR/2013/REC-sparql11-http-rdf-update-20130321/
The collection lexicon must be enabled on your database when using the semantics REST services or use the GRAPH '?g' construct in a SPARQL query. For details, see Configuring the Database to Work with Triples in the Semantics Developer's Guide.
To load triples, send a PUT or POST request to the /graphs service with one of the following forms of URL, depending upon whether you wish to address a specific named graph or the default graph:
http://host:port/version/graphs?graph=graph-uri http://host:port/version/documents?default
For details, see Loading Triples Using the REST API and Supported RDF Triple Formats in Semantics Developer's Guide.
You can also create, update, and delete triples and graphs with SPARQL Update by sending a POST request to the /graphs/sparql
service. For example, the following SPARQL update request inserts a triple into the default graph:
PREFIX dc: <http://purl.org/dc/elements/1.1/> INSERT DATA { <http://example/book0> dc:title "A default book" }
If you place the above SPARQL Update request into a file named update.sparql, then the following request to the /graphs/sparql
performs the requested update:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X POST -i --data-binary @./update.sparql \ -H "Content-type:application/sparql-update" \ -H "Accept:application/sparql-results+xml" \ 'http://localhost:8000/LATEST/graphs/sparql'
When you put your SPARQL Update request in the HTTP request body, the request Content-type must be application/sparql-update
. You can also specify your update using URL encoded form data. For more details and examples, see SPARQL Update with the REST Client API in the Semantics Developer's Guide.
Documents you create with the REST Client API have a read permission for the rest-reader
role and an update permission for the rest-writer
role by default. To restrict access to particular users, create custom roles rather than assigning users to the default rest-*
roles. For example, you can use a custom role to restrict users in one group from seeing documents created by another.
For details, see Controlling Access to Documents and Other Artifacts.
You can transform content during ingestion by applying custom transform. A transform is an XQuery module or XSLT stylesheet you write and install using /config/transforms/{name}
. For details, see Working With Content Transformations.
To apply a transform when creating or updating a document, add the transform
parameter to your request. If the transform expects parameters, specify them using trans:
paramName parameters. That is, your request should be of the form:
http://host:port/version/documents?...&transform=name&trans:arg=value
The following example applies a transform installed under the name example that expects a parameter named reviewer:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT \ -d@./the-body -H "Content-type: application/xml" \ 'http://localhost:8000/LATEST/documents?uri=/doc/theDoc.xml&transform=example&trans:reviewer=me'
For a complete example, see XQuery Example: Adding an Attribute During Ingestion or XSLT Example: Adding an Attribute During Ingestion.
To a retrieve document from the database, make a GET request to the /documents
service. You can retrieve just the contents, just the metadata, or both contents and metadata. This section covers the following topics:
To retrieve multiple documents in a single request, see Reading and Writing Multiple Documents.
To retrieve a document from the database, construct a GET request of the following form:
http://host:port/version
/documents?uri=doc_uri
HTTP content type negotiation is not supported. If the HTTP Accept header is not set, MarkLogic Server uses the file extension on the document URI to determine the response content type, based on the server-wide MIME type mapping definitions. See Mimetypes in the Admin Interface.
Though content negotiation is not supported, you can use the transform feature to apply server-side transformations to the content before the response is constructed. For details, see Working With Content Transformations.
To retrieve multiple documents in a single request, see Reading and Writing Multiple Documents.
To retrieve metadata about a document without retrieving the contents, construct a GET request of the following form:
http://host:port/version/documents?uri=doc_uri&category=metadata_category
Where category
can appear multiple times, with the values described in Metadata Categories.
When constructing the request:
category
parameter to the type of metadata to retrieve. Specify category
multiple times to request more than one type of metadata.Accept
header or the format
parameter.For details on metadata categories and formats, see Working with Metadata.
Use the format
parameter or the Accept
header to specify the format of the metadata. If both format
and Accept
are set, format
takes precedence. If neither format
nor Accept
is specified, XML is assumed. For details, see Controlling Input and Output Content Type.
To retrieve metadata as XML, set format
to xml or set the Accept
header to application/xml
. To retrieve metadata as JSON, set format
to json or set the Accept
header to application/json
.
To retrieve content and metadata for a document in a single request, construct GET request to a URL of the form:
http://host:port/version/documents?uri=doc_uri&category=content&category=metadata_category
Where category
can appear multiple times, with the values described in Metadata Categories.
The request response is a multipart/mixed
message, with the metadata in the first body part and content in the second body part. The Content-Type headers for the parts are determined as follows:
format
parameter, which you can set to either xml
or json
; the default is xml. For details on metadata format, see Working with Metadata. The following example command retrieves a document and its metadata in a single request:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X GET \ -H "Accept: multipart/mixed;boundary=BOUNDARY" \ 'http://localhost:8000/LATEST/documents?uri=/xml/box.xml&category=metadata&category=content&format=xml' --BOUNDARY Content-Type: application/xml Content-Length: 518 <?xml version="1.0" encoding="UTF-8"?> <rapi:metadata uri="/xml/box.xml" xsi:schemaLocation="http://marklogic.com/rest-api/database dbmeta.xsd" xmlns:rapi="http://marklogic.com/rest-api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <rapi:collections> <rapi:collection>shapes</rapi:collection> <rapi:collection>squares</rapi:collection> </rapi:collections> <rapi:permissions/> <prop:properties xmlns:prop="http://marklogic.com/xdmp/property"/> <rapi:quality>0</rapi:quality> <rapi:metadata-values/> </rapi:metadata> --BOUNDARY Content-Type: text/xml Content-Length: 128 <?xml version="1.0" encoding="UTF-8"?> <data><mybox>This is my box. There are many like it, but this one is mine.</mybox></data> --BOUNDARY--
HTTP content negotiation is not supported, but custom server-side content transformations can be applied using the transform
parameter. For details, see Retrieving the Contents of a Document and Working With Content Transformations.
You can apply custom transforms to a document before returning it to the requestor. A transform is a JavaScript module, XQuery module, or XSLT stylesheet you write and install using /config/transforms/{name}
. For details, see Working With Content Transformations.
You can configure a default transform that is automatically applied whenever a document is retrieved. You can also specify a per-request transform using the transform
request parameter. If there is both a default transform and a per-request transform, the transforms are chained together, with the default transform running first. Thus, the output of the default transform is the input to the per-request transform:
To configure a default transformation, set the document-transform-out
configuration parameter for the REST Client API instance. Instance-wide parameters are set using /config/properties
. For details, see Configuring Instance Properties.
To specify a per-request transform, add the transform
parameter to your request. If the transform expects parameters, specify them using trans:
paramName parameters. That is, your request should be of the form:
http://host:port/version/documents?...&transform=name&trans:arg=value
The following example applies a transform installed under the name example that expects a parameter named reviewer:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X GET \ -H "Accept: application/xml" \ 'http://localhost:8000/LATEST/documents?uri=/doc/theDoc.xml&transform=example&trans:reviewer=me'
This section focuses on modifying a portion of an existing XML or JSON document or its metadata. To learn about inserting or updating an entire document or its metadata, see Loading Content into the Database.
This section covers the following topics:
A partial update is an update you apply to a portion of a document or metadata. For example, inserting an XML element or attribute or changing the value associated with a JSON property. You can only apply partial content updates to XML and JSON documents. You can apply partial metadata updates to any document type.
A patch is a partial update descriptor, expressed in XML or JSON, that tells MarkLogic Server where to apply an update and what update to apply. A patch is a wrapper XML element or JSON object that encapsulates one or more update operations.
Use a partial update to do the following operations:
To perform a partial update, send a POST or PATCH request to the /documents
service with a patch in the request body. For example, the following patch descriptor inserts a new <child/>
element as the last child of the element located through the XPath expression /data
:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/data" position="last-child"> <child>the last one</child> </rapi:insert> </rapi:patch>
Assuming the above patch is saved to the file patch.xml
, the following command uses a POST request to apply the patch to the document with the URI /doc/example.xml
.
$ curl --anyauth --user user:password -X POST -d @./patch.xml -i \ -H "Content-type: application/xml" \ -H "X-HTTP-Method-Override: PATCH" \ http://localhost:8000/LATEST/documents?uri=/doc/example.xml
The following example is an equivalent request using PATCH instead of POST:
$ curl --anyauth --user user:password -X PATCH -d @./patch.xml -i \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/doc/example.xml
For details, see Basic Steps for Patching Documents.
You can apply multiple updates in a single request. You can patch both content and metadata in a single request.
Content negotiation is not supported: A content patch must match the content type of the target document. That is, you cannot submit a JSON patch for an XML document or an XML patch for a JSON document.
If a patch contains multiple operations, they are applied independently to the target document. That is, within the same patch, one operation does not affect the context
or select
results or the content changes of another. Each operation in a patch is applied independently to every matched node. If any operation in a patch fails with an error, the entire patch fails.
Content transformations are not directly supported in a partial update. However, you can implement a custom replacement content generation function to achieve the same effect. For details, see Constructing Replacement Data on the Server.
To perform a partial update of an XML or JSON document, or of document metadata, send a POST or PATCH request to the /documents
service with a URL of the following form:
http://host:port/version/documents?uri=doc_uri
The body of the request must contain a content patch, as described in XML Patch Reference and JSON Patch Reference. You can patch metadata and content in the same request by using the category request parameter; for details, see Patching Metadata.
When constructing your request, follow these guidelines:
uri
parameter to the URI of the target document in the database.category
request parameter to content
, metadata
, and/or one of the metadata subcategories. The default is content
.Content-type
to either application/xml
or application/json
. When patching content, you must use the content type that matches the target document; only XML and JSON are supported.X-HTTP-Method-Override
to PATCH
to tell MarkLogic Server this is a partial update request.New content that is added or replaced can be specified directly in the patch, or generated on MarkLogic Server by a replacement content generator function. For details, see Constructing Replacement Data on the Server.
This section summarizes the structure of the XML patch structure used to describe partial updates to XML documents and document metadata. Each section includes a syntax summary, a description of the components, and an example.
The following elements, all in the namespace http://marklogic.com/rest-api, are covered. Start with the <patch/>
wrapper.
The top level wrapper element around a partial update descriptor. A <patch/>
has the following structure:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert /> <rapi:replace /> <rapi:replace-insert /> <rapi:delete /> <rapi:replace-library /> </rapi:patch>
All elements are optional. The operations can occur multiple times. The <replace-library/>
can occur at most once and is only required if you use user-defined functions to generate replacement content server-side; for details, see Constructing Replacement Data on the Server.
A patch can only replace a single node.
For example, the following patch includes an insertion, deletion, and replacement:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/inventory/history" position="last-child"> <modified>2012-11-5</modified> </rapi:insert> <rapi:delete select="saleExpirationDate"/> <rapi:replace select="price" apply="ml.multiply">1.1</rapi:replace> </rapi:patch>
Where a patch operation includes new XML content, such as an element insertion, the new content must use namespaces appropriate to the target document. Namespaces declared in the root <patch/>
node are in scope for this content. For details, see Managing XML Namespaces in a Patch.
Insert a new element, attribute, text node, comment, or processing instruction in an XML document or in document metadata. An <insert/>
element has the following structure:
<insert context=xpath-expr position=pos-selector
cardinality=
occurrence>
content-to-insert
</insert>
For example, the following patch adds a <modified/>
element as the last child of every <history/>
node that matches the XPath expression /inventory/history
:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/inventory/history" position="last-child"> <modified>2012-11-5</modified> </rapi:insert> </rapi:patch>
For additional examples, see XML Examples of Partial Updates.
The following table summarizes the parts of an <insert/>
element.
Component | Req'd | Description |
---|---|---|
@context= xpath-expr |
Y | An XPath expression that selects an existing node(s) or attribute on which to operate. Namespaces declared on the root When inserting an attribute, If no matches are found for the The path expression is restricted to the subset of XPath for which |
@position= pos-selector |
Y | Where to insert the content, relative to the node(s) selected by @context . The attribute value must be one of before , after , or last-child . |
@cardinality= occurrence |
N | The required occurrence of matches to |
content-to-insert | Y | When inserting elements, text, comments, and processing directives, specify the new nodes as they should appear in the target document. When inserting attributes, specify the attribute(s) on a <rapi:attribute-list a1="v1" a2="v2"/> |
Replace an existing element or attribute. If no matching element or attribute exists, the operation is silently ignored. A <replace/>
element has the following structure:
<replace select=xpath-expr cardinality=occurrence apply=func-name> replacement-content </replace>
For example, the following patch replaces the first <child/>
element of <parent/>
:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace select="/parent/child[1]"> <child>REPLACED</child> </rapi:replace> </rapi:patch>
For additional examples, see XML Examples of Partial Updates.
You can also supply a content generation builtin or user-defined function using @apply
, using the format below. For example, you can use the builtin ml.multiply
function to multiply the current value of an element that contains numeric data, without needing to know the current value.
<rapi:replace select="my-elem" apply=ml.multiply>5</rapi:replace>
For details, see Constructing Replacement Data on the Server.
The following table summarizes the parts of a <replace/>
element.
Component | Req'd | Description |
---|---|---|
@select= xpath-expr |
Y | An XPath expression that selects an existing node(s) or attribute to replace. Namespaces declared on the root The path expression is restricted to the subset of XPath for which The selected node cannot be the target of any other operation in the patch. The ancestor of the selected node may not be modified by a |
@cardinality= occurrence |
N | The required occurrence of matches to |
replacement-content | N | The content with which to replace the selected node or attribute. If present, this must be a single node. If there is no replacement-content, you must specify a content generation function using To replace an element, specify either a replacement element or text. When you use text, the text replaces just the content of the target element. To replace an element with a text node, wrap the text in a <rapi:text>replacement text</rapi:text> To replace an attribute, use either a <rapi:attribute-list my-attr="new-value" /> <rapi:text>new-value</rapi:text> |
@apply= func-name |
N | The local name of a replacement content generation function. If you do not specify a function, the operation must include replacement-content. If you name a user-defined function, the For details, see Constructing Replacement Data on the Server. |
Replace an element or attribute; if there are no existing matching elements or attributes, perform an insertion operation instead. A <replace-insert/>
element has the following structure:
<replace-insert select=xpath-expr context=xpath-expr position=pos cardinality=occurrence apply=func-name> replacement-content </replace-insert>
For example, the following patch replaces the first <grandchild/>
element of a <child/>
of <parent/>
elements. If no <child/>
element has a <grandchild/>
element, one is inserted in every <child/>
of a <parent/>
element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace-insert context="/parent/child" select="grandchild[1]" position="last-child"> <grandchild>CHANGED</grandchild> </rapi:replace-insert> </rapi:patch>
For additional examples, see XML Examples of Partial Updates.
You can also use @apply
to specify a content generation builtin or user-defined function for generating dynamic content. For details, see Constructing Replacement Data on the Server.
The following table summarizes the parts of a <replace-insert/>
element.
Component | Req'd | Description |
---|---|---|
@select= xpath-expr |
Y | An XPath expression that selects an existing node(s) or attribute to replace. Namespaces declared on the root The path expression is restricted to the subset of XPath for which If no matches are found for the The selected node cannot be the target of any other operation in the patch. The ancestor of the selected node may not be modified by a delete, replace, or replace-insert operation in the same patch. |
replacement-content | N | The content with which to replace the selected node or attribute. If there is no replacement-content, you must specify a content generation function using To replace an element, specify either a replacement element or text. When you use text, the text replaces just the content of the target element. To replace an element with a text node, wrap the text in a <rapi:text>replacement text</rapi:text> To replace an attribute, use either a <rapi:attribute-list my-attr="new-value" /> <rapi:text>new-value</rapi:text> |
@context= xpath-expr |
Y | An XPath expression that selects an existing node(s) or attribute on which to operate if the The path expression is restricted to the subset of XPath for which When inserting an attribute, If no matches are found for either the The ancestor of the selected node may not be modified by a delete, replace, or replace-insert operation in the same patch. |
@position= pos-selector |
Y | If @select does not match anything, where to insert the content, relative to the node(s) selected by @context . The attribute value must be one of before , after , or last-child . Ignored for attributes. |
@cardinality= occurrence |
N | The required occurrence of matches to |
@apply= func-name |
N | The local name of a replacement content generation function. If you do not specify a function, the operation must include replacement-content. If you name a user-defined function, the For details, see Constructing Replacement Data on the Server. |
Remove an element or attribute from an existing node. A <delete/>
element has the following structure:
<delete select=xpath-expr cardinality=occurrence />
For example, the following patch deletes the first <child/>
element of a <parent/>
and removes the my-attr
attribute from the <parent/>
element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:delete select="/parent/child[1]" /> <rapi:delete select="/parent/@my-attr" /> </rapi:patch>
For additional examples, see XML Examples of Partial Updates.
The following table summarizes the parts of a <delete/>
element.
Component | Req'd | Description |
---|---|---|
@select= xpath-expr |
Y | An XPath expression that selects the node(s) or attribute(s) to delete. Namespaces declared on the root The path expression is restricted to the subset of XPath for which The selected node cannot be the target of any other operation in the patch. The ancestor of the selected node may not be modified by a delete, replace, or replace-insert operation in the same patch. |
@cardinality= occurrence |
N | The required occurrence of matches to |
Specify an XQuery library module that contains user-defined replacement content generation functions. These functions can be used in @apply
on <replace/>
and <replace-insert/>
operations. For details, see Constructing Replacement Data on the Server.
For example, the following patch uses the function my-ns:my-func
in the library module in the with the URI /my.domain/my-module.xqy
.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace-library at="/my.domain/my-module.xqy" ns="my-ns" /> <rapi:replace select="/parent/child[1]" apply="my-func" /> </rapi:patch>
For additional examples, see Constructing Replacement Data on the Server.
The following table summarizes the parts of a <replace-library/>
element.
The patch descriptor must be in the namespace http://marklogic.com/rest-api
. To distinguish the <patch/>
elements from elements in your document, you should include an alias for the patch descriptor namespace. For example:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> ... </rapi:patch>
Declare additional namespace aliases for the content described by the patch. Namespaces declared on the <patch/>
root element are in scope in @context
and @select
path expressions and in the content portion of <insert/>
, <replace/>
and <replace-insert/>
elements.
For example, if you patch a document with the following contents:
<parent xmlns="http://my/namespace"> <child>first</child> </parent>
Then your <patch/>
should either define http://my/namespace
as the default namespace or define a namespace alias for it. For example, the following patch inserts a <child/>
element when you define a default namespace:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api" xmlns="http://my/namespace"> <rapi:insert context="/parent" position="last-child"> <child>last</child> </rapi:insert> </rapi:patch>
The following is the same patch, using an explicit namespace alias of my-ns
:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api" xmlns:my-ns="http://my/namespace"> <rapi:insert context="/my-ns:parent" position="last-child"> <my-ns:child>last</my-ns:child> </rapi:insert> </rapi:patch>
Failure to use namespace declarations properly in a patch can lead to surprising results. For example, if you did not include a namespace declaration for http://my/namespace
, the patch would not work because the context XPath expression would not match any elements in the target document. Similarly, if you include a namespace alias but do not use it in the definition of the new child, the new child element would be inserted in no namespace: <child xmlns="">...</child>
.
This section includes the following examples of applying a partial update to an XML document or metadata:
Many of the examples include extra whitespace to improve readability. You should not do likewise unless you want extra whitespace in your target document. Whitespace in the body of an <insert/>
, <replace/>
, or <replace-insert/>
operation is usually significant.
The examples in this section can be applied using commands similar to the following, assuming you copy the sample input document to a file called example.xml
and the patch to a file called patch.xml
.
# Windows users, see Modifying the Example Commands for Windows # Create the example document $ curl --anyauth --user user:password -X PUT -d @./example.xml \ -i -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml # Apply the patch $ curl --anyauth --user user:password -X POST -d @./patch.xml \ -i -H "Content-type: application/xml" \ -H "X-HTTP-Method-Override: PATCH" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml # Retrieve the results curl --anyauth --user user:password -X GET \ -i -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml
The following patch inserts an <INSERTED/>
element before each <child/>
element matched by the context expression.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/parent/child" position="before"> <INSERTED/> </rapi:insert> </rapi:patch>
The table below shows how applying the patch changes the target document.
The following patch adds two attributes, my-attr1
and my-attr2
, on the second <child/>
element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/parent/child[2]"> <rapi:attribute-list my-attr1="val1" my-attr2="val2" /> </rapi:insert> </rapi:patch>
The table below shows how applying the patch changes the target document.
The following patch inserts a text node before the second <child/>
element matched by the context expression.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/parent/child[2]" position="before">INSERTED</rapi:insert> </rapi:patch>
The table below shows how applying the patch changes the target document.
Before Update | After Update |
---|---|
<parent> <child>one</child> <child>two</child> <child>three</child> </parent> |
<parent> <child>one</child> INSERTED <child>two</child> <child>three</child> </parent> |
The following patch inserts a comment as the first child of every <parent/>
element matched by the context expression.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/parent/*[1]" position="before"> <!-- INSERTED --> </rapi:insert> </rapi:patch>
The table below shows how applying the patch changes the target document.
The following patch performs several insert operations on the target document:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:insert context="/parent/child" position="before"> <INSERTED/> </rapi:insert> <rapi:insert context="/parent/child[2]" position="before">INSERTED</rapi:insert> <rapi:insert context="/parent/child[2]"> <rapi:attribute-list my-attr="val" /> </rapi:insert> <rapi:insert context="/parent/*[1]" position="before"> <!-- INSERTED --> </rapi:insert> </rapi:patch>
The table below shows how applying the patch changes the target document. Notice that the insert operations act independently on the target document, rather than interacting with each other. For example, the comment insertion operation, which uses the context expression /parent/*[1]
, inserts the comment before the first original <child/>
element, not before the <INSERTED/>
element added by one of the other operations in the patch.
The following patch replaces the first <child/>
node with a new element, replaces the contents of the second <child/>
, and replaces the third <child/>
with a text node.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <!-- replace an entire element --> <rapi:replace select="/parent/child[1]"> <REPLACED /> </rapi:replace> <!-- replace the element contents --> <rapi:replace select="/parent/child[2]"> REPLACED </rapi:replace> <!-- replace an element with a text node --> <rapi:replace select="/parent/child[3]"> <rapi:text>REPLACED</rapi:text> </rapi:replace> </rapi:patch>
The table below shows how applying the patch changes the target document.
Before Update | After Update |
---|---|
<parent> <child>one</child> <child>two</child> <child>three</child> </parent> |
<parent> <REPLACED /> <child>REPLACED</child> REPLACED </parent> |
The following patch demonstrates two methods of replacing the value of an attribute. The first <replace/>
uses a <text/>
wrapper and the second uses an <attribute-list>
container element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace select="/parent/@attr1"> <rapi:text>REPLACE-1</rapi:text> </rapi:replace> <rapi:replace select="/parent/child/@attr2"> <rapi:attribute-list attr2="REPLACE-2"/> </rapi:replace> </rapi:patch>
The table below shows how applying the patch changes the target document.
The following patch replaces the first <grandchild/>
element of a <child/>
of <parent/>
elements. If no <child/>
element has a <grandchild/>
element, one is inserted in every <child/>
of a <parent/>
element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace-insert context="/parent/child" select="grandchild[1]" position="last-child"> <grandchild>CHANGED</grandchild> </rapi:replace-insert> </rapi:patch>
The following table illustrates applying this patch to two documents, one for which there is a match to the replacement target, and one for which there is no match. In the first case, the node matching the @select
expression (relative to @context
) is replaced with the patch contents. In the second case, there are no matching nodes, so the content in the patch is inserted into all nodes that match the @context
expression.
The following patch is equivalent, except that the <grandchild/>
elements are replaced with a text node:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace-insert context="/parent/child" select="grandchild[1]" position="last-child"> <rapi:text>CHANGED</rapi:text> </rapi:replace-insert> </rapi:patch>
The following patch replaces /parent/child/@my-attr
and inserts /parent/child/@new-attr
.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:replace-insert select="@my-attr" context="/parent/child"> REPLACED </rapi:replace-insert> <rapi:replace-insert select="@new-attr" context="/parent/child"> <rapi:attribute-list new-attr="INSERTED" /> </rapi:replace-insert> </rapi:patch>
The following table illustrates the results of applying this patch:
The following patch deletes all <grandchild/>
elements and deletes an attribute from the <parent/>
element.
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api"> <rapi:delete select="/parent/child/grandchild"/> <rapi:delete select="/parent/@my-attr"/> </rapi:patch>
The table below shows how applying the patch changes the target document.
Before Update | After Update |
---|---|
<parent my-attr="val"> <child/> <child> <grandchild/> <grandchild/> </child> </parent> |
<parent> <child/> <child></child> </parent> |
This section summarizes the structure of the JSON patch structured used to describe partial updates to JSON documents. Each section includes a syntax summary, a description of component JSON properties, and an example.
This topic covers the following properties of a patch:
The insert
, replace
, replace-insert
, and delete
patch operations all require constructing one or more path expressions that identify the content to be changed. To accurately address JSON with XPath, you need to understand the MarkLogic JSON document model. For details, see Traversing JSON Documents Using XPath in the Application Developer's Guide.
Specify the path language (JSONPath or XPath) with which the patch specifies the document components targeted by an patch operation, such as the value of the select
and context
properties of a replace-insert
operation.
The default value is "xpath"
, so you only need to include this property in your patch when you want to use JSONPath.
The use of JSONPath is deprecated.
The following example sets the path language to JSONPath:
{ "pathlang": "jsonpath", "patch": [ { "insert": { "context": "$.parent.child", "position": "last-child", "content": { "new-key": "new-value" } }} ]}
To learn more about addressing JSON with XPath, see Limitations of JSON Path Expressions and Traversing JSON Documents Using XPath in the Application Developer's Guide.
A patch is the top level wrapper object for applying partial updates to JSON documents. A JSON patch has the following structure. A patch object can contain multiple operations.
{"patch": [ insert, replace, replace-insert, delete, replace-library ] }
All subobjects are optional. The operations (insert
, replace
, replace-insert
) can occur multiple times. You can only have one replace-library
, and it is only required if you use user-defined functions to generate replacement content.
For example, the following patch describes an insert and a replace operation. For more examples, see JSON Examples of Partial Update.
{"patch": [ { "insert": { "context": "/parent/child", "position": "last-child", "content": { "new-key": "new-value" } }}, { "replace": { "select": "/parent/child[0]", "content": "new-value" }} ]}
Insert new JSON properties or array elements. An insert
operation has the following structure:
{ "insert": { "context": path-expr, "position": pos-selector, "content": new-content, "cardinality": occurrence } }
For example, if /parent/child
is the path to an array valued JSON property, then the following patch inserts the value "INSERTED" after each element of the array:
{"insert": { "context": "/parent/child", "position": "after", "content": "INSERTED" }}
The following table summarizes the components of an insert
operation.
See Example: Insert for examples of this patch.
JSON Property | Req'd | Description |
---|---|---|
"context": path-expr |
Y | An XPath or JSONPath expression that selects an existing JSON property or array element on which to operate. The expression can select multiple items. If no matches are found for the The path expression is restricted to the subset of XPath (or its JSON Path equivalent) that can be used to define an index. For details, see Path Expressions Usable in Patch Operations. |
"position" : pos-selector |
Y | Where to insert the content, relative to the JSON property or value selected by context . The pos-selector must be one of "before" , "after" , or "last-child" . For details, see Specifying Position in JSON. |
"content": new-content |
Y | The new content to be inserted. |
cardinality: occurrence |
N | The required occurrence of matches to |
Replace an existing JSON property or array element. If no matching JSON property or array element exists, the operation is silently ignored. A replace operation has the following structure:
{ "replace": { "select" : path-expr, "content" : new-value, "cardinality": occurrence, "apply" : func-name } }
For example, the following patch replaces the value of the first array element in the JSON property named "child" that is a subobject of the JSON property named "parent":
{"patch": [ {"replace": { "select": "/parent/child[1]", "content": "REPLACED" }} ]}
For additional examples, see JSON Examples of Partial Update.
You can use apply
to specify a content generation builtin or user-defined function for generating dynamic content. For details, see Constructing Replacement Data on the Server.
The following table summarizes the parts of a replace
operation.
See Example: Replace for examples of this patch.
Component | Req'd | Description |
---|---|---|
"select": path-expr |
Y | An XPath or JSONPath expression that selects the JSON property or array element to replace. If no matches are found for the The path expression is restricted to the subset of XPath that can be used to define an index (or its JSONPath equivalent). For details, see Path Expressions Usable in Patch Operations. The selected item(s) cannot be the target of any other operation in the patch. The ancestor of the selected item may not be modified by a |
"content" : new-value |
N | The replacement value. If there is no new-value, you must specify a content generation function using If |
cardinality: occurrence |
N | The required occurrence of matches to |
"apply": func-name |
N | The local name of a replacement content generation function. If you do not specify a function, the operation must include a If you name a user-defined function, the For details, see Constructing Replacement Data on the Server. |
In certain cases, separate insert and replace operations with mutually exclusive XPaths are necessary.
Replace a property or array item; if there are no existing matching properties, perform an insertion operation instead. A replace-insert
operation has the following structure:
{ "replace-insert": { "select" : path-expr, "context" : path-expr, "position": pos-selector, "cardinality": occurrence, "content" : replacement-content, "apply" : func-name } }
Optionally, you can supply a builtin or user-defined content generation function name using apply
. If the function does not expect parameters, you can omit content when using apply
. For details, see Constructing Replacement Data on the Server.
For example, the following patch replaces the value of "target"
with "new-value"
in the array value of /parent/child
, if it exists. If no such value is found, then "new-value"
is inserted as the last element in the array addressable as /parent/array-node('child')
.
{ "patch": [ { "replace-insert" : { "select": "/parent/child[. = 'target']", "context": "/parent/array-node('child')", "position": "last-child", "content": "new-value" }} ]}
For additional examples, see JSON Examples of Partial Update.
The following table summarizes the parts of a replace-insert
operation.
See Example: Replace-Insert for examples of this patch.
Component | Req'd | Description |
---|---|---|
"select" : path-expr |
Y | An XPath or JSONPath expression that selects the property or array element to replace. If no matches are found for the The path expression is restricted to the subset of XPath that can be used to define an index, or its JSONPath equivalent. For details, see Path Expressions Usable in Patch Operations. The selected item(s) cannot be the target of any other operation in the patch. The ancestor of the selected item may not be modified by a |
replacement-content | N | The content with which to replace the selected value. If there is no replacement-content, you must specify a content generation function using If |
"context" : path-expr |
Y | An XPath or JSONPath expression that selects an existing property or array element on which to operate. The expression can select multiple items. If no matches are found for the either the The path expression is restricted to the subset of XPath that can be used to define an index, or its JSONPath equivalent. For details, see Path Expressions Usable in Patch Operations. The ancestor of the selected node may not be modified by a |
"position" : pos-selector |
N | If |
cardinality: occurrence |
N | The required occurrence of matches to |
"apply" : func-name |
N | The local name of a replacement content generation function. If you do not specify a function, the operation must include a If you name a user-defined function, the For details, see Constructing Replacement Data on the Server. |
Remove a property or array element. A delete
operation has the following structure:
{ "delete": { "select" : path-expr, "cardinality": occurrence } }
For example, the following patch deletes any JSON property named child
that is contained in the property named parent
.
{"patch": [ { "delete" : { "select": "/parent//child" } } ]}
For additional examples, see JSON Examples of Partial Update.
The following table summarizes the parts of a delete
operation.
See Example: Delete for examples of this patch.
Component | Req'd | Description |
---|---|---|
select : path-expr |
Y | An XPath or JSONPath expression that selects the JSON property or array element to remove. If no matches are found for the The path expression is restricted to the subset of XPath that can be used to define an index, or its JSONPath equivalent. For details, see Path Expressions Usable in Patch Operations. The selected item(s) cannot be the target of any other operation in the patch. The ancestor of the selected item may not be modified by a |
cardinality: occurrence |
N | The required occurrence of matches to |
Specify an XQuery library module that contains user-defined replacement content generation functions. These functions can be used in the apply
property of a replace
or replace-insert
operation. A patch can contain at most one replace-library
. For details, see Constructing Replacement Data on the Server.
For example, the following patch uses the function my-ns:my-func
in the library module in the with the URI /my.domain/my-module.xqy
.
{ "patch": [ {"replace-library": { "at": "/my.domain/my-module.xqy", "ns": "my-ns" }}, {"replace": { "select": "/inventory[name eq 'orange']/price", "apply": "my-func" }} ]}
For additional examples, see Constructing Replacement Data on the Server.
The following table summarizes the parts of a <replace-library/>
element.
This section includes the examples of applying a partial update with a JSON patch. The following topics are covered:
To understand these examples, it is important that you understand how to use XPath to address JSON document components. For details, see Working With JSON in the Application Developer's Guide.
The examples in this section can be applied using commands similar to the following, assuming you copy the sample input document to a file called example.json
and the patch to a file called patch.json
.
# Windows users, see Modifying the Example Commands for Windows # Create the example document $ curl --anyauth --user user:password -X PUT -d @./example.json \ -i -H "Content-type: application/json" \ http://localhost:8000/LATEST/documents?uri=/docs/example.json # Apply the patch $ curl --anyauth --user user:password -X POST -d @./patch.json \ -i -H "Content-type: application/json" \ -H "X-HTTP-Method-Override: PATCH" \ http://localhost:8000/LATEST/documents?uri=/docs/example.json # Retrieve the results curl --anyauth --user user:password -X GET \ -i -H "Accept: application/json" \ http://localhost:8000/LATEST/documents?uri=/docs/example.json
The following patch inserts a new property in the root object in the first child position, inserts a new array element value in the child3
subject object, inserts a new property in the root object in last child position.
{ "patch": [ { "insert": { "context": "/parent/child1", "position": "before", "content": { "INSERT1": "INSERTED1" } }}, { "insert": { "context": "/parent/child3[1]", "position": "after", "content": "INSERTED2" }}, { "insert": { "context": "/node()", "position": "last-child", "content": { "INSERT3": "INSERTED3" } }} ] }
The following table shows how applying the patch changes the target document.
To insert a property if and only if it does not already exist, use a predicate in the context path expression to test for existence. For example, the following patch will insert a property named TARGET only if the object does not already contain such a property:
{ "patch": [ { "insert": { "context": "/parent[fn:empty(TARGET)]", "position": "last-child", "content": { "TARGET": "INSERTED" } }} ]}
This patch must use the last-child
position because the context selects the node that will contain the new property.
For more details on the JSON document model and traversing JSON documents with XPath, see Working With JSON in the Application Developer's Guide.
The patch in this example demonstrates the following types of replacement operations:
The following patch replaces one property with another, replaces the simple value of a property, and replaces the array value of a property.
{ "patch": [ { "replace": { "select": "/parent/child1", "content": { "REPLACE1": "REPLACED1" } }}, { "replace": { "select": "/parent/child2", "content": "REPLACED2" }}, { "replace": { "select": "/parent/child3[1]", "content": "REPLACED3" }}, { "replace": { "select": "/parent/array-node('child4')", "content": [ "REPLACED4a", "REPLACED4b" ] }}, { "replace": { "select": "/parent/child5", "content": "REPLACED5" }}, { "replace": { "select": "/parent/array-node('child6')/node()[2]", "content": [ "REPLACED6a", "REPLACED6b" ] }}, { "replace": { "select": "/parent/child7[2]", "content": "REPLACED7" }} ]}
The following table shows how applying the patch changes the target document. Further explanation follows the table.
The following table breaks the patch down into sections and describes how each operation works.
For more details on the JSON document model and traversing JSON documents with XPath, see Working With JSON in the Application Developer's Guide.
The following patch demonstrates replace-insert
on array values. The patch includes two operations for each child of parent, one that results in a replace and one that results in an insert.
{ "patch": [ { "replace-insert": { "select": "/parent/child1[1]", "context": "/parent/array-node('child1')", "position": "last-child", "content": "REPLACED1" }}, { "replace-insert": { "select": "/parent/child1[3]", "context": "/parent/child1[2]", "position": "after", "content": "INSERTED1" }}, { "replace-insert": { "select": "/parent/child2[. = 'c2_v1']", "context": "/parent/node('child2')", "position": "last-child", "content": "REPLACED2" }}, { "replace-insert": { "select": "/parent/child2[. = 'INSERTED2']", "context": "/parent/node('child2')", "position": "last-child", "content": "INSERTED2" }}, { "replace-insert": { "select": "/parent/child3[c3_a]", "context": "/parent/node('child3')", "position": "last-child", "content": { "REPLACED3" : "REPLACED_V" } }}, { "replace-insert": { "select": "/parent/child3[INSERTED3]", "context": "/parent/node('child3')", "position": "last-child", "content": { "INSERTED3" : "INSERTED_V" } }} ]}
The following table shows how applying the patch changes the target document.
Recall that the select
path identifies the content to replace. When working with an array item, an absolute path is usually required. For example, consider the following patch operation:
{ "replace-insert": { "select": "/parent/child1[1]", "context": "/parent/array-node('child1')", "position": "last-child", "content": "REPLACED1" }}
The goal is to replace the value of the first item in the array value of /parent/child1
if it exists. If the array is empty, insert the new value. That is, one of these two transformations takes place:
{"parent"{"child1": ["c1_v1", "c1_v2"], ... } ==> {"parent"{"child1": ["REPLACED1", "c1_v2"], ... } {"parent"{"child1": [], ... } ==> {"parent"{"child1": ["REPLACED1"], ... }
The select
expression, /parent/child1[1]
, must target an array item value, while the context expression must target the containing array node by referencing /parent/array-node("child1")
. You cannot make the select expression relative to the context expression in this case.
Note that while you can target an entire array item value with replace-insert
, you cannot target just the value of a property. For example, consider the following array:
"child3": [ { "c3_a": "c3_v1" }, { "c3_b": "c3_v2" } ]
You can use replace-insert
on the entire object-valued item { "c3a": "c3v1" }, as is done in the example. However, you cannot construct an operation that targets just the value of the property in the object ("c3_v1"). The replacement of the property value is fundamentally different from inserting a new item in the array. A property (as opposed to the containing object) can only be replaced by deleting it and then inserting a new item.
You cannot use a replace-insert
operation to conditionally insert or replace a property because the insertion content and the replacement content requirements differ. However, you can use separate insert and replace operations within the same patch to achieve the same effect.
For example, the following patch inserts a new property named TARGET if it does not already exists, and replaces its value if it does already exist:
{ "patch": [ { "insert": { "context": "/parent[fn:empty(TARGET)]", "position": "last-child", "content": { "TARGET": "INSERTED" } }}, { "replace": { "select": "/parent/TARGET", "content": "REPLACED" }} ]}
The following table illustrates the effect of applying the patch:
For more details on the JSON document model and traversing JSON documents with XPath, see Working With JSON in the Application Developer's Guide.
The following patch removes properties and array elements at various levels of a document. See the table below for how the patch affects the example content.
{{ "patch": [ { "delete" : { "select": "/props/node('anyType')" }}, { "delete" : { "select": "/props/objOrLiteral" }}, { "delete" : { "select": "/props/array-node('arrayVal')" }}, { "delete" : { "select": "/arrayItems/all" }}, { "delete" : { "select": "/arrayItems/byPos[1]" }}, { "delete" : { "select": "/arrayItems/byVal[. = 'DELETE']" }}, { "delete" : { "select": "/arrayItems/byName[DELETE]" }} ] }
The following table shows how applying the patch changes the target document.
Note that when removing properties, you must either use a named node step to identify the target property or be aware of the value type. Consider these 3 select
path expressions from the example program:
/props/node('anyType') /props/objOrLiteral' /props/array-node('arrayVal')
The first path is type agnostic: /props/node("anyType"). This expression selects any nodes named anyType
, regardless of the type of value. The second path, /props/objOrLiteral
, deletes the entire name-value pair only if the value is an object or literal (string, number, boolean). If the value of the property is an array, it deletes the items in the array. That is, this operation applied to the original document will delete the contents of the array, not the arrayVal
property:
pb.remove('/props/arrayVal') ==> arrayVal: [ ]
The third form, /props/array-node('arrayVal'), deletes the arrayVal
property, but it will only work on properties with array type. Therefore, if you need to delete a property by name without regard to its type, use path of the form /path/to/parent/node('propName')
.
For more details on the JSON document model and traversing JSON documents with XPath, see Working With JSON in the Application Developer's Guide.
You can partially update metadata for any document type, including XML, JSON, text, and binary. To update a portion of the metadata for a document, send a POST request to the /documents
service with a URI of the following form.
http://host:port/version/documents?uri=document-uri&category=category
The category parameter should either be metadata
or one of the metadata sub-categories of collections
, properties
, permissions
, metadata-values
, and quality
. The category affects what pieces of metadata MarkLogic Server considers for updating. For example, if you use category=permissions
, but your patch only contains an operation applied to properties, the patch has no effect.
Category does not affect how you construct path expressions in a patch. That is, context
and select
paths within the patch are not relative to the specified metadata category.
The request body must contain an XML or JSON patch descriptor. Construct your metadata patch to apply to the structure described in Working with Metadata, using the same syntax and semantics as for a content patch. For details, see in XML Patch Reference or JSON Patch Reference.
Document quality (the <quality/>
XML element or quality
JSON property) can only be the target of a replace operation.
You can update content and metadata in the same request by including operations on both in your patch descriptor and setting the category request parameter appropriately. For example:
http://localhost:8000/LATEST/documents?uri=/my.xml&category=content&category=metadata
When patching content and metadata in the same request, the usual content type restrictions apply: You can only apply content patches to XML and JSON documents, and you cannot use a JSON patch descriptor on XML content, or vice versa.
Since JSON does not use qualified names, you can construct a context
or select
path that addresses both metadata and content items. If your content contains JSON properties with the same name as the metadata properties (properties
, collections
, permissions
, metadataValues
, and quality
) and you cannot construct an unambiguous path, do not combine content and metadata partial updates in the same request.
Paths for context
and select
can be relative or absolute with respect to the metadata structure. For example, both of the following operations insert a document into a new collection, using different context
paths.
The following example is a patch that performs multiple metadata updates: Add the target document to a new collection, add or replace a property, and replace the document quality:
When patching properties using XML, you must explicitly declare the namespace http://marklogic.com/xdmp/property
on the root <patch/>
element because the <properties/>
metadata element is in a different namespace from the other metadata elements.
Values metadata (category=metadata-values
) is represented differently in XML and JSON. The equivalent of the XML metadata-values
element is a JSON property named metadataValues
, and where XML has metadata-value
child elements to represent each key-value pair, JSON has key:
value child properties. For details, see Working with Metadata.
You can use builtin or user-defined replacement functions to generate the content for a partial update operation dynamically on MarkLogic Server. The builtin functions support simple arithmetic and string manipulation. For example, you can use a builtin function to increment the current value of numeric data or concatenate strings. For more complex operations, create and install a user-defined function.
The following topics are covered:
You can only use replacement generator functions with the replace
and replace-insert
operations. The REST Client API ships with a set of builtin arithmetic and string manipulation functions. If your patch includes a replace-library
specification, you can also create user-defined functions.
The following example increases every price
in an inventory
element or object by 10% by using the builtin ml.multiply
function to multiply the current value by 1.1.
The following example uses a user-defined function to double the price
in every inventory
element or object. The dbl
function is implemented by the XQuery module /my.domain/my-lib.xqy
, which uses the module namespace http://my/ns
. The dbl
function does not expect any argument values, so there is no content included in the replace
operation.
Use the following guidelines to specify a replacement generator function in a patch descriptor:
apply
XML attribute or JSON property to the function local name.replace-library
XML element or JSON property in the patch
to specify the module containing the function implementation. The implementation module must be installed in the modules database of the REST API instance.content
JSON property. See the example below.If a function expects a single argument, you can place the value directly in the content or in a <rapi:value/>
XML element or $value
JSON property. The previous example places the value (1.1) directly in the content section of the patch.
If a function expects multiple arguments, enclose each value in a <rapi:value/>
XML element or $value
JSON property. For example, the following patch uses the builtin function ml.concat-between
which expects two string parameters.
In XML, the implicit datatype of arguments is xs:untypedAtomic
, though a generator function can cast the value to the expected parameter type. For example, the builtin arithmetic functions cast to xs:double
when possible. Use @xsi:type
to explicitly specify a type on a value.
The following example specifies an explicit xs:date
datatype. Note that you must declare the xs and xsi
namespace aliases on the root of your patch
:
<rapi:patch xmlns:rapi="http://marklogic.com/rest-api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <rapi:replace select="/elem" apply="my-func"> <rapi:value xsi:type="xs:date">2013-03-15</rapi:value> </rapi:replace> </rapi:patch>
In JSON, use $datatype
to explicitly specify an xsi:type
for a $value
. Omit the xs:
namespace prefix on the type name. The following example explicitly specifies xs:date
as the datatype for the replace function input parameter:
{"patch": [ {"replace": { "select": "/my/data", "apply": "ml.concat-between", "content": [ { "$value" : "2013-03-15", $datatype: "date"} ] } } ] }
The REST Client API includes several builtin server-side functions you can use to dynamically generate the content for a replace
or replace-insert
operation. For example, you can use a builtin function to increment the current value of a data item.
All the builtin function names have a ml.
prefix. You cannot use this prefix on user-defined replacement generator functions.
The builtin arithmetic functions are equivalent to the XQuery +
, -
, *
, and div
operators, and accept values castable to the same datatypes. That is, numeric, date, dateTime, duration, and Gregorian (xs:gMonth
, xs:gYearMonth
, etc.) values. The operand type combinations are as supported by XQuery; for details, see http://www.w3.org/TR/xquery/#mapping. All other functions expect values castable to string.
The table below lists the builtin replacement generator functions provided by the REST Client API. In the table, $current represents the current value of the target of the replace operation; $arg and $argN represent argument values passed in by the patch.
This section describes how to implement a custom replacement content constructor in XQuery. You can use such a function to generate content for the replace
and replace-insert
operations. You can also implement a constructor in Server-Side JavaScript; for details, see Writing a JavaScript User-Defined Replacement Constructor.
You must install your implementation in the modules database associated with your REST API instance before you can use it. For details, see Installing or Updating a User-Defined Replace Library.
A user-defined replacement constructor function has the following interface:
declare function module-ns:func-name( $current as node()?, $args as item()* ) as node()*
The current node ($current
) is empty only when the function is invoked as an insert on behalf of a replace-insert
.
The argument list supplied by the operation is passed through args
. You are responsible for validating the argument values. If the content supplied by the patch operation is JSON array or a sequence of XML <rapi:value/>
elements, then $args
is the result of calling the fn:data
function on each value. If an explicit datatype is specified by the patch operation, the cast is applied before invoking your function.
Your function should report errors using fn:error
and RESTAPI-SRVEXERR
. For details, see Reporting Errors.
The following example XQuery library module implements two replacement content constructors, mylib:dbl
to double the value in a target node, and my-lib:min
to replace the value of a node with the minimum value of the current node and a sequence of values passed in by the patch. For simplicity, this example skips most of the input data validation that a production implementation should include.
xquery version "1.0-ml"; module namespace my-lib = "http://marklogic.com/example/my-lib"; (: Double the value of a node :) declare function my-lib:dbl( $current as node()?, $args as item()* ) as node()* { if ($current/data() castable as xs:decimal) then let $new-value := xs:decimal($current) * 2 return typeswitch($current) case number-node() (: JSON :) return number-node {$new-value} case element() (: XML :) return element {fn:node-name($current)} {$new-value} default return fn:error((), "RESTAPI-SRVEXERR", ("400", "Bad Request", fn:concat("Not an element or number node: ", xdmp:path($current)) )) else fn:error((), "RESTAPI-SRVEXERR", ("400", "Bad Request", fn:concat("Non-decimal data: ", $current))) }; (: Find the minimum value in a sequence of value composed of :) (: the current node and a set of input values. :) declare function my-lib:min( $current as node()?, $args as item()* ) as node()* { if ($current/data() castable as xs:decimal) then let $new-value := fn:min(($current, $args)) return typeswitch($current) case element() (: XML :) return element {fn:node-name($current)} {$new-value} case number-node() (: JSON :) return number-node {$new-value} default return fn:error((), "RESTAPI-SRVEXERR", ("400", "Bad Request", fn:concat("Not an element or number node: ", xdmp:path($current)))) else fn:error((), "RESTAPI-SRVEXERR", ("400", "Bad Request", fn:concat("Non-decimal data: ", $current))) };
The following patch snippet uses the above module, assuming the module is installed in the modules database with the URI /ext/replace/my-lib.xqy
:
This section describes how to implement a custom replacement content constructor in Server-Side JavaScript. You can use such a function to generate content for the replace
and replace-insert
operations. You can also implement a constructor in XQuery; for details, see Writing an XQuery User-Defined Replacement Constructor.
You must install your implementation in the modules database associated with your REST API instance before you can use it. For details, see Installing or Updating a User-Defined Replace Library.
A user-defined replacement constructor function has the following interface:
function funcname(current, args)
Where the parameters have the following semantics:
replace-insert
operation that is inserting new content.rapi:values
XML element or $value
JSON property. It can be null, a single item or a Sequence
, depending on whether the operation defines zero, one, or multiple values.You are responsible for validating the args values. The value of each item in args is the result of calling the fn:data
function on each value defined by the operation. If an explicit datatype is specified by the patch operation, the cast is applied before invoking your function.
Your function must return zero, one, or more nodes containing the generated content. Use a Sequence to return multiple nodes.
Your function should report errors using fn:error
and RESTAPI-SRVEXERR
. For details, see Reporting Errors.
The following example implements two replacement content constructors, dbl
to double the value in a target node, and min
to replace the value of a node with the minimum value of the current node and a sequence of values passed in by the patch. For simplicity, this example skips most of the input data validation that a production implementation should include. The example functions operate on either an XML element or a JSON number node. In production, you would likely have different functions for different content types.
'use strict'; function dbl(current,args) { switch(xdmp.nodeKind(current)) { case "number": { return new NodeBuilder() .addNumber(fn.data(current).valueOf() * 2) .toNode(); } case "element": { const currentValue = fn.data(current).valueOf(); if (xdmp.castableAs( "http://www.w3.org/2001/XMLSchema", "decimal", currentValue)) { return new NodeBuilder() .addElement(fn.nodeName(current).toString(), xs.string(currentValue * 2)) .toNode(); } else { fn.error(null, 'RESTAPI-SRVEXERR', Sequence.from([ '400', 'Bad Request', 'Non-decimal data: ' + xdmp.path(current)])); } } default: fn.error(null, 'RESTAPI-SRVEXERR', Sequence.from([ '400', 'Bad Request', 'Not an element or number node: ' + xdmp.path(current)])); } }; function min(current, args) { switch(xdmp.nodeKind(current)) { case "number": { return new NodeBuilder() .addNumber(Math.min( ...args.toArray().concat(fn.data(current).valueOf()))) .toNode(); } case "element": { const currentValue = fn.data(current).valueOf(); if (xdmp.castableAs( "http://www.w3.org/2001/XMLSchema", "decimal", currentValue)) { return new NodeBuilder() .addElement(fn.nodeName(current).toString(), xs.string(Math.min(...args.toArray().concat(currentValue)))) .toNode(); } else { fn.error(null, 'RESTAPI-SRVEXERR', Sequence.from([ '400', 'Bad Request', 'Non-decimal data: ' + xdmp.path(current)])); } } default: fn.error(null, 'RESTAPI-SRVEXERR', Sequence.from([ '400', 'Bad Request', 'Not an element or number node: ' + xdmp.path(current)])); } }; exports.dbl = dbl; exports.min = min;
The following patch snippet uses the dbl
function of the above module, assuming the module is installed in the modules database with the URI /ext/replace/my-lib.sjs
:
The following patch snippet illustrates how to pass arguments to the min function of the same module. Two numeric values are passed into the min function, in the form of a Sequence
.
To install user-defined replacement constructor functions, place your function(s) into an XQuery or Server-Side JavaScript library module and install the module in the modules database associated with your REST API instance.
Your implementation, including any dependent libraries, must be installed in the modules database associated with your REST API instance. The simplest way to achieve this is to use the /ext
service that is part of the REST Client API. For details, see Managing Dependent Libraries and Other Assets.
To install your library using the /ext
service, send a PUT request to a URL of one of the following forms, with your library module implementation in the request body:
http://host:port/version/ext/your/path/your-lib.xqy?perm:perm http://host:port/version/ext/your/path/your-lib.sjs?perm:perm
If you do not specify any permissions, the module will only be executable by users with the rest-admin
role.
When you use /ext
to install your module, MarkLogic Server installs the module in the request body into the modules database associated with your REST API instance, at a URI derived from the above URL, beginning with /ext
. For example, the following command installs the library module with the URI /ext/replace/my-lib.xqy
:
$ curl --anyauth --user user:password -X PUT -d @./my-lib.xqy \ -i -H "Content-type: application/xquery" \ http://localhost:8000/LATEST/ext/replace/my-lib.xqy?perm:my-user:execute
The following patch snippet uses the module URI in the value of the at XML attribute or JSON property in a replace-lib
directive:
<rapi:replace-library at="/ext/replace/my-lib.xqy" ns="http://marklogic.com/example/my-lib" />
If your library module requires dependent libraries, you can install them in the same database directory (/ext/replace/
, in the above example). The /ext
service allows you to manage at both the directory and file level. For details, see Managing Dependent Libraries and Other Assets.
Use the same procedure to update your implementation after initial installation.
The insert
and replace-insert
patch operations include a position member that defines the point of insertion when coupled with a context expression. This section describes the details of how position affects the insertion point. The following topics are covered:
The @position
of an <insert/>
or <replace-insert/>
operation specifies where to insert new content, relative to the context
node or attribute. Position can be one of the following values:
before
: Insert before the element or attribute identified by @context
. The @context
must not target the root element.after
: Insert after the element or attribute identified by @context
. The @context
must not target the root element.last-child
: Insert as the last child of the element identified by @context
. The @context
must target a node, not an attribute.The last-child
is not meaningful for operations on attributes.
The following table shows example combinations of @context
and @position
and the resulting insertion point for new content. The insertion point is indicated by ***.
The position
property in a patch specifies where to insert new content relative to the context
item. Position can be one of the following values:
before
: Insert before the property or array element value selected by context
.after
: Insert after the property or array element value selected by context
.last-child
: Insert into the value of the target property or array, in the position of last child. The value selected by context
must be an object or array.The same usage applies whether inserting on behalf of an insert
operation or a replace-insert
operation.
You cannot use last-child
to insert a property as an immediate child of the root node of a document. Use before or after instead. For details, see Limitations of JSON Path Expressions.
The following table shows example combinations of context
and position
and the resulting insertion point for new content. The insertion point is indicated by ***.
A patch operation uses one or more path expressions to identify the target of the operation.
For performance and security reasons, the path expression used in the context
and select
specifications of a patch operation is limited to a subset of XPath. JSONPath expressions are constrained by equivalent limitations.
For details, see Patch Feature of the Client APIs in the XQuery and XSLT Reference Guide.
You can replace just the value of a property, but you cannot replace an entire property with a new one in a single operation.
For example, given content of the following form, you can use a replace operation to change the value property a from 1 to 2:
{ "a": 1 }
However, you cannot use a replace operation to change the content to the following:
{ "b": "anyvalue" }
In this example, the path expression /a addresses a number node with name a and value 1. The select expression in the replace operation enables you to replace the value of the selected name, but not the name.
To achieve the desired effect, you must first delete the existing property, and then insert a new one.
This limitation also means you cannot use a replace-insert
operation to perform an operation such as insert this property if it doesn't exist; otherwise, replace it. However, you can use separate insert
and replace
operations in a single patch to perform an operation such as insert this property if it doesn't exist; otherwise, replace its value. For an example, see JSON Examples of Partial Update.
When applying partial updates to JSON documents, you can specify the target of a patch operation using JSONPath expressions in the context
and select
properties of a patch operation. This section gives a brief overview of JSONPath syntax. For a complete description of JSONPath, see http://goessner.net/articles/JsonPath/.
The default path expression language is XPath. Using JSONPath is deprecated. To use JSONPath, you must set the pathlang
property to jsonpath
. For details, see pathlang.
[?(@.value < 10)]
.The set of JSONPath expressions usable for document operations like partial update is limited to JSONPath equivalent to XPath expressions that can be used to define a path range index. For details, see Path Expressions Usable in Patch Operations.
The following table contains some simple JSONPath examples that satisfy the restrictions. The bold text indicates what is selected by each expression.
To perform a document check, construct a HEAD request to a URL of the form:
http://host:port/version/documents?uri=document_uri
The following example sends a HEAD request for an XML document:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X HEAD \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/xml/box.xml ... Content-type: application/xml Server: MarkLogic Connection: close HTTP/1.1 200 Document Retrieved vnd.marklogic.document-format: xml Content-type: application/xml Server: MarkLogic Connection: close
Issuing the same request on a non-existent document returns status 404:
$ curl --anyauth --user user:password -X HEAD \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/xml/dne.xml ... Content-type: application/xml Server: MarkLogic Connection: close HTTP/1.1 404 Not Found Content-type: application/xml Server: MarkLogic Connection: close
This section covers using the /documents
and /search
services to remove documents from the database. The following topics are covered:
To remove a document and its metadata from the database, construct a DELETE request with a URL of the form:
http://host:port/version/documents?uri=document_uri
When you delete a document, its metadata is also deleted.
You can remove multiple documents (or reset their metadata) by specifying multiple URIs. Optimistic locking is not supported when you specify multiple URIs.
To remove or reset just metadata for a document, construct a DELETE request with a URL of the form:
http://host:port/version/documents?uri=document_uri&category=metadata_category
The category
parameter can appear multiple times, with the values described in Metadata Categories. Resetting permissions resets the document permissions to the default permissions for the current user. Resetting quality resets the document quality to the default (0).
Deleting a binary document with extracted metadata stored in a separate XHTML document also deletes the XHTML metadata document. For more information, see Working with Binary Documents.
In addition to removing multiple documents by URI as described in Removing a Document or Metadata, you can remove all documents in a collection or in a database directory.
To remove all documents in a collection, send a DELETE request with a URL of the following form:
http://host:port/version/search?collection=collection_name
Similarly, to remove all documents in a directory, send a DELETE request with a URL of the following form:
http://host:port/version/search?directory=directory_name
Where directory_name is the name of a directory in the database. The directory name must include a trailing /.
You can specify only one collection or one directory in a single request.
Failing to specify either a directory or a collection removes all documents in the database.
Removing a document also removes its metadata. Deleting a binary document with extracted metadata stored in a separate XHTML document also deletes the XHTML metadata document. For more information, see Working with Binary Documents.
The following example remove all documents in the /plays directory:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -i -X DELETE \ http://localhost:8000/LATEST/search?directory=/plays/ ... HTTP/1.1 204 Updated Server: MarkLogic Content-Length: 0 Connection: close
To remove all documents in the database, send a DELETE request with a URL of the following form:
http://host:port/version/search
Clearing the database requires the rest-admin
role or equivalent.
There is no confirmation or other safety net when you clear the database in this way. Creating a backup is advised.
The following example removes all documents and metadata from the content database:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -i -X DELETE \ http://localhost:8000/LATEST/search
To remove the triples in a graph, send a DELETE to the /graphs
service with a URL of one of the following forms:
http://host:port/version/graphs?graph=graph-urihttp://host:port/version/graphs?default
The /graphs
service only affects triples stored in a triple document (a document with a <sem:triples>
root element). Therefore, if the graph includes triples embedded in normal XML documents, the embedded triples are unaffected and the graph will continue to exist.
You can also delete a graph by using an empty graph in a PUT request to the /graphs
service.
An application using optimistic locking creates a document only when the document does not exist and updates or deletes a document only when the document has not changed since this application last changed it. However, optimistic locking does not actually involve placing a lock on document.
Optimistic locking is useful in environments where integrity is important, but contention is rare enough that it is useful to minimize server load by avoiding unnecessary multi-statement transactions.
This section covers the following topics:
Consider an application that reads a document, makes modifications, and then updates the document in the database with the changes. The traditional approach to ensuring document integrity is to perform the read, modification, and update in a multi-statement transaction. This holds a lock on the document from the point when the document is read until the update is committed. However, this pessimistic locking blocks access to the document and incurs more overhead on the App Server.
With optimistic locking, the application does not hold a lock on a document between read and update. Instead, the application saves the document state on read, and then checks for changes at the time of update. The update fails if the document has changed between read and update. This is a conditional update.
Optimistic locking is useful in environments where integrity is important, but contention is rare enough that it is useful to minimize server load by avoiding unnecessary multi-statement transactions. The REST Client API also supports multi-statement transactions. For details, see Managing Transactions.
The REST Client API uses content versioning to implement optimistic locking. When content versioning is enabled, MarkLogic Server associates an opaque version id with a document. The version id changes each time you update the document. The version id is returned when you read a document, and you can pass it back in an update or delete operation to test for changes prior to commit.
Content versioning in the REST Client API does not implement document versioning. When content versioning is enabled, MarkLogic Server does not keep multiple versions of a document or track what changes occur. The version id can only be used to detect that a change occurred.
Using optimistic locking in your application requires the following steps:
update-policy
REST instance configuration property. Enable optimistic locking using the update-policy
instance configuration property, as described in Configuring Instance Properties. For example, the following command sets update-policy
to version-optional
:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT \ -d'{"update-policy":"version-optional"}' \ -H "Content-type: application/json" \ http://localhost:8000/LATEST/config/properties
The update-policy
property can be set to merge-metadata
(the default), version-required
, or version-optional
. Set the property to version-required
if you want every document update or delete operation to use optimistic locking. Set the property to version-optional
to allow selective use of optimistic locking.
The update-policy
property replaces the older content-versions
policy; content-versions
is deprecated. Setting update-policy
to version-optional
is equivalent to setting content-versions
to optional
. Setting update-policy
to version-required
is equivalent to setting content-versions
to required
.
The table below describes how each setting for this property affects document operations.
When optimistic locking is enabled, a version id is included in the response when you read documents. You can only obtain a version id if optimistic locking is enabled by setting update-policy
; for details, see Enabling Optimistic Locking.
You can obtain a version id for use in conditional updates in the following ways:
/documents
. The version id is returned in the ETag header of the response./documents
with multiple URIs. The version id is returned in the Content-Disposition header of each content part in the multipart response. You can mix and match these methods for obtaining a version id.
The following example command returns the version id for a single document:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -i -X HEAD \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 200 Document Retrieved Content-type: application/xml ETag: "13473172834878540" Server: MarkLogic Connection: close
The following example command returns the version id for multiple documents in a single request:
curl --anyauth --user user:password -X GET -i \ -H "Accept: multipart/mixed; boundary=BOUNDARY" \ http://localhost:8000/LATEST/documents?uri=doc1.xml\&uri=doc2.json ... --BOUNDARY Content-Type: application/xml Content-Disposition: attachment; filename="doc1.xml"; category=content; format=xml; versionId=14075140367230760 Content-Length: 87 ...document contents... --BOUNDARY Content-Type: application/json Content-Disposition: attachment; filename="doc2.json"; category=content; format=json; versionId=14075140367230760 Content-Length: 15 ...document contents...
For details on multi-document requests, see Reading and Writing Multiple Documents.
To apply a conditional update, supply a version id on your update operation. The version id is ignored if optimistic locking is not enabled; for details, see Enabling Optimistic Locking.
When a document update includes a version id, MarkLogic Server checks for changes to the version id before committing the update (or delete) operation. If the version id has changed, the update fails. In a multi-document update, the entire batch of updates is rejected if any conditional update fails.
You can supply a version id on an update in the following ways:
/documents
./documents
.The following example performs a conditional update of a single document by passing a version id in the If-Match request header:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -i -X PUT -d"<modified-data/>" \ -H "Content-type: application/xml" \ -H "If-Match: 13473769780393030" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml
The following POST body excerpt for a multi-document update unconditionally updates the first document (doc1.xml
) and conditionally updates the second document (doc2.xml
). Note that if update-policy
is set to version-required
, the request will fail if doc1.xml
already exists because no version id is supplied for it.
--BOUNDARY Content-Type: application/xml Content-Disposition: attachment; filename="doc1.xml" Content-Length: 87 ...document contents... --BOUNDARY Content-Type: application/json Content-Disposition: attachment; filename="doc2.json"; versionId=14075140367230760 Content-Length: 15 ...document contents... --BOUNDARY--
The following command applies the above update, if the complete POST body is in the file /example/optimistic-locking
.
$ curl --anyauth --user user:password -X POST -i \ --data-binary @/example/optimistic-locking \ -H "Content-type: multipart/mixed; boundary=BOUNDARY" \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents
For details on multi-document requests, see Reading and Writing Multiple Documents.
The following example demonstrates using optimistic locking to conditionally update a single document. Both a successful and a failed update are shown.
This example uses a PUT request to demonstrate a conditional update. For a POST, PATCH, or DELETE operation, follow a similar procedure, passing the version id in the If-Match header of your update or delete request. For an equivalent multi-document update, pass the version id in the Content-Disposition header of each content part.
update-policy
to version-optional
:# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT \ -d'{"update-policy":"version-optional"}' \ -H "Content-type: application/json" \ http://localhost:8000/LATEST/config/properties
$ curl --anyauth --user user:password -i -X PUT -d"<data/>" \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml
$ curl --anyauth --user user:password -i -X GET \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 200 Document Retrieved vnd.marklogic.document-format: xml Content-type: application/xml ETag: "13473769780393030" Server: MarkLogic Content-Length: 47 Connection: close <?xml version="1.0" encoding="UTF-8"?> <data/>
$ curl --anyauth --user user:password -i -X PUT -d"<modified-data/>" \ -H "Content-type: application/xml" \ -H "If-Match: 13473769780393030" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 204 Content Updated Server: MarkLogic Content-Length: 0 Connection: close
$ curl --anyauth --user user:password -i -X PUT -d"<data/>" \ -H "Content-type: application/xml" \ -H "If-Match: 13473769780393030" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 412 Precondition Failed Content-type: application/xml Server: MarkLogic Content-Length: 370 Connection: close <?xml version="1.0"?> <rapi:error xmlns:rapi="http://marklogic.com/rest-api"> <rapi:status-code>412</rapi:status-code> <rapi:status>Precondition Failed</rapi:status> <rapi:message-code>RESTAPI-CONTENTWRONGVERSION</rapi:message-code> <rapi:message>RESTAPI-CONTENTWRONGVERSION: (err:FOER0000) Content version mismatch: uri: /docs/example.xml version: 13473788748796580</rapi:message> </rapi:error>
You can use content versioning to refresh a copy of a document stored on the client only if the document in the database has been modified. This section covers the following topics:
Enable content versioning using the update-policy
instance configuration property, as described in Configuring Instance Properties.
The default update policy is merge-metadata
. If you set update-policy
to version-required
or version-optional
, content versioning is enabled, and a GET or HEAD request to /documents
returns a version id in the ETag response header.
Enabling content versioning can affects document insertion, update, and deletion. For details, see Enabling Optimistic Locking.
Content versioning in the REST Client API does not implement document versioning. When content versioning is enabled, MarkLogic Server does not keep multiple versions of a document or track what changes occur. The version id can only be used to detect that a change occurred.
When content versioning is enabled, sending a GET request to /documents
with a version id in the If-None-Match HTTP header only retrieves a new copy of the document if it has changed relative to the version id in the header.
The update-policy
property replaces the older content-versions
property; content-versions
is deprecated. Setting update-policy
to version-optional
is equivalent to setting content-versions
to optional
. Setting update-policy
to version-required
is equivalent to setting content-versions
to required
.
Follow the procedure below to use content version for cache refreshing. For a complete example, see Example: Refreshing a Cached Document.
update-policy
instance configuration property to version-optional
or version-required
; see Enabling Content Versioning./documents
. The response includes the version id in the ETag header./documents
with the version id from Step 2 in the If-None-Match HTTP header.If the current version id matches the one in the If-None-Match header, no document is retrieved and MarkLogic Server returns status 304. If the current version id differs from the one in the If-None-Match header, the document is returned, along with the new version id in the ETag response header.
The following example demonstrates using content versioning to refresh a client-side document cache. The example includes a case where the document is unchanged in the database, as well as the case where the local cache is out of date.
update-policy
to version-optional
:# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT \ -d'{"update-policy":"version-optional"}' \ -H "Content-type: application/json" \ http://localhost:8000/LATEST/config/properties
$ curl --anyauth --user user:password -i -X PUT -d"<data/>" \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml
$ curl --anyauth --user user:password -i -X GET \ -H "Accept: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 200 Document Retrieved vnd.marklogic.document-format: xml Content-type: application/xml ETag: "13473769780393030" Server: MarkLogic Content-Length: 47 Connection: close <?xml version="1.0" encoding="UTF-8"?> <data/>
$ curl --anyauth --user user:password -i -X GET \ -H "Accept: application/xml" \ -H "If-None-Match: 13473769780393030" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 304 Content Version Not Modified ETag: "13473769780393030" Server: MarkLogic Content-Length: 0 Connection: close
$ curl --anyauth --user user:password -i -X PUT -d"<modified-data/>" \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 204 Content Updated Server: MarkLogic Content-Length: 0 Connection: close
$ curl --anyauth --user user:password -i -X GET \ -H "Accept: application/xml" \ -H "If-None-Match: 13473769780393030" \ http://localhost:8000/LATEST/documents?uri=/docs/example.xml ... HTTP/1.1 200 Document Retrieved vnd.marklogic.document-format: xml Content-type: application/xml ETag: "13473770707201670" Server: MarkLogic Content-Length: 56 Connection: close <?xml version="1.0" encoding="UTF-8"?> <modified-data/>
This section covers the following topics:
This section provides a brief summary of binary document types. For details, see Working With Binary Documents in the Application Developer's Guide.
MarkLogic Server can store binary documents in three representations:
Small and large binary documents are created automatically for you, depending on the document size. External binary documents cannot be created using the REST Client API.
Large binary documents can be streamed out of the database using Range requests. For details, see Streaming Binary Content.
Streaming binary content out of the database avoids loading the entire document into memory. You can stream binary documents by sending GET requests to /documents
that include range requests under following conditions:
The following example requests the first 500K of the binary document with URI /binaries/large.jpg
:
# Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -i -o piece.jpg -X GET \ -H "Accept: application/jpg" -r "0-511999" \ http://localhost:8000/LATEST/documents?uri=/binaries/large.jpg ... HTTP/1.1 206 Binary Part Retrieved Content-type: application/jpeg Content-Range: bytes 0-511999/533817 Server: MarkLogic Content-Length: 511999 Connection: close
Most document write operations, such as PUT, POST, and PATCH on the /documents
service enable you to work with temporal documents by exposing the following request parameters:
temporal-collection
: The URI of the temporal collection into which the new document should be inserted, or the name of the temporal collection that contains the document being updated. temporal-document
: The logical URI of the document in the temporal collection; the temporal collection document URI. This is equivalent to the first parameter of the temporal:statement-set-document-version-uri
XQuery function or of the temporal.statementSetDocumentVersionUri
Server-Side JavaScript function.source-document
: The temporal collection document URI of the document being operated on. This parameter is only applicable when updating existing documents. This parameter facilitates working with documents with user-maintained version URIs.system-time
: The system start time for an update or insert.To create temporal documents, you must use an endpoint that accepts a caller-specified URI. You cannot use POST /v1/documents?extension={ext}
to create a temporal document because MarkLogic generates the document URI when you use this method.
During an update operation, if you do not specify source-document
or temporal-document
, then the uri
request parameter indicates the source document. If you specify temporal-document
, but do not specify source-document
, the temporal-document URI identifies the source document.
The uri
request parameter always refers to the output document URI. When the MarkLogic manages the version URIs, the document URI and temporal document collection URI have the same value. When the user manages version URIs, they can be different.
Use POST:/v1/documents/protection
to protect a temporal document from operations such as update, delete, and wipe for a specified period of time. This method is equivalent to calling the temporal:document-protect
XQuery function or the temporal.documentProtect
Server-Side JavaScript function.
Use POST:/v1/temporal/collections/{name}
to advance LSQT on a temporal collection. This method is equivalent to calling the temporal:advance-lsqt
XQuery function or the temporal.advanceLsqt
Server-Side JavaScript function.
For more details, see the Temporal Developer's Guide and specific methods in the MarkLogic REST API Reference.
The /documents
service supports inserting, updating, and retrieving document metadata. Metadata is the properties, collections, permissions, quality and key-value metadata of content.
Metadata manipulation is most often exposed by the REST Client API through a category
URL parameter. Metadata can be passed around as either XML or JSON, usually controlled through either an HTTP header or a format
URL parameter. For specifics of a particular method, see the MarkLogic REST API Reference.
This section covers the following topics related to metadata storage and retrieval:
Where the REST Client API accepts specification of metadata categories, the following categories are recognized:
The metadata
category is shorthand for all the other categories. That is, metadata
includes collections, permissions, properties, key-value metadata and quality.
Some requests also support a content
category as a convenience for requesting or updating both metadata and document content in a single request.
The metadata-values
category represents a metadata field. This type of metadata is expressed as simple key-value pairs and you must configure a database field on a key before you can search it. While similar in some ways to document properties, this type of metadata is stored separately from the associated document and can be operated on like any other field. For more details, see Metadata Fields in the Administrator's Guide.
Metadata contains information about document collections, permissions, properties, quality, and key-value metadata. The format is fully described by the schema file:
MARKLOGIC_INSTALL_DIR/Config/restapi.xsd
The following is a summary of the structure of the metadata. All elements are in the namespace http://marklogic.com/rest-api. You can have 0 or more <collection/>
, <permission/>
, <metdata-values>
, <metadata-value/>
or property child elements. There can be only one <quality/>
element. The element name and contents of each document property element depends on the property.
<metadata xmlns="http://marklogic.com/rest-api"> <collections> <collection>collection-name</collection> </collections> <permissions> <permission> <role-name>name</role-name> <capability>capability</capability> </permission> </permissions> <properties> <property-element/> </properties> <quality>integer</quality> <metadata-values> <metadata-value key="keyName">value</metadata-value> </metdata-values> </metadata>
The following example shows a document in two collections, with one permission, two properties, and one key-value metadata item.
<rapi:metadata xmlns:rapi="http://marklogic.com/rest-api"> <rapi:collections> <rapi:collection>shapes</rapi:collection> <rapi:collection>squares</rapi:collection> </rapi:collections> <rapi:permissions> <rapi:permission> <rapi:role-name>hadoop-user-read</rapi:role-name> <rapi:capability>read</rapi:capability> </rapi:permission> </rapi:permissions> <prop:properties xmlns:prop="http://marklogic.com/xdmp/property"> <myprop>this is my prop</myprop> <myotherprop>this is my other prop</myotherprop> </prop:properties> <rapi:quality>0</rapi:quality> <rapi:metadata-values> <rapi:metadata-value key="level">high</rapi:metadata-value> </rapi:metadata-values> </rapi:metadata>
Metadata contains information about document collections, permissions, properties, quality, and key-value metadata. A block of metadata can contain multiple collections, permissions and properties, but only 1 quality. The structure of each child of the properties
JSON property depends on the property contents.
{ "collections" : [ string ], "permissions" : [ { "role-name" : string, "capabilities" : [ string ] } ], "properties" : { property-name : property-value }, "quality" : integer "metadataValues": { key: value } }
The following example shows a document in two collections, with one permission, two document properties, and two key-value metadata items.
{ "collections": [ "shapes", "squares" ], "permissions": [ { "role-name": "hadoop-user-read", "capabilities": [ "read" ] } ], "properties": { "myprop": "this is my prop", "myotherprop": "this is my other prop" }, "quality": 0, "metadataValues": { "level": "high", "rating": 5 } }
In most cases, your application should work with properties in a consistent format. That is, if you insert or update properties as XML, then you should retrieve them in XML. If you insert or update properties as JSON, you should retrieve them in JSON.
You should only insert document property data as JSON when you can specify the content type, such as through the request or part header of POST:/v1/documents
. Do not use the prop
request parameter of PUT:/v1/documents
to insert document properties with JSON values as such input is untyped.
Internally, document properties are always stored as XML. When you insert a user-defined property using JSON, the XML representation is an XML element in the namespace http://marklogic.com/xdmp/json/basic
with a local name that matches the property name in JSON. When you retrieve the property data as JSON, it is converted from XML back to JSON.
As long as you handle the data consistently, the conversion to and from XML is largely transparent to your application. However, you need to be aware of the XML representation when searching properties. Also, the implementation of transforms and extensions only sees the XML representation.
If you configure an index based on a user-defined property inserted using JSON, treat them as XML elements and use the http://marklogic.com/xdmp/json/basic
in your configuration.
Protected system properties such as last-updated
cannot be modified by your application. When retrieved as JSON, such protected properties are wrapped in an object with the JSON property name $ml.prop
. For example:
{ "properties": { "$ml.prop": { "last-updated": "2013-11-06T10:01:11-08:00" } } }
The following example code adds a document property expressed as JSON to /my/doc.json
:
$ curl --anyauth --user user:password -X PUT -i \ -H "Content-type: application/json" \ -d '{"properties": {"pname":"pvalue"}}' \ 'http://localhost:8000/LATEST/documents?uri=/doc/my.json&category=properties'
If you retrieve the properties of /doc/my.json
as JSON, you get back what was inserted. The internal representation as XML is hidden from your application. For example:
$ curl --anyauth --user user:password -X GET \ -H "Accept: application/json" \ 'http://localhost:8000/LATEST/documents?uri=/doc/my.json&category=properties' {"properties":{"pname":"pvalue"}}
However, if you retrieve the properties as XML or examine them using the Explore feature of Query Console, you will see the XML representation. For example:
$ curl --anyauth --user user:password -X GET \ -H "Accept: application/xml" \ 'http://localhost:8000/LATEST/documents?uri=/doc/my.json&category=properties' <rapi:metadata uri="/doc/my.json" ...> <prop:properties xmlns:prop="http://marklogic.com/xdmp/property"> <pname type="string" xmlns="http://marklogic.com/xdmp/json/basic"> pvalue </pname> </prop:properties> </rapi:metadata>
If you use the REST Client API to ingest a large number of documents at one time and you find the performance unacceptable, you might see a small performance improvement by disabling metadata merging. This topic explains the tradeoff and how to disable metadata merging.
The performance gain from disabling metadata merging is modest, so you are unlikely to see significant performance improvement from it unless you ingest a large number of documents. You might see a performance gain under one of the following circumstances:
You cannot disable metadata merging in conjunction with update policies version-optional
or version-required
.
Metadata merging is disabled by default for multi-document write requests, as long as the request includes content for a given document. For details, see Understanding When Metadata is Preserved or Replaced.
Disabling metadata merging effectively eliminates the distinction between inserting a new document and updating an existing document, with respect to metadata handling.
Metadata merging is enabled by default. When you update metadata, the metadata in your update is merged with existing metadata. You can extend or update metadata without re-specifying unmodified document properties, collections, permissions, document quality, or key-value metadata. Similarly, when you update document content without including any metadata updates, the existing metadata is preserved.
When metadata merging is disabled, updating any metadata on a document overwrites all metadata for the document with the metadata provided in the request (plus default values for unspecified metadata categories). A content update that does not include any metadata resets the document metadata to the default values.
For example, if you set permissions on a document when you initially insert it into the database, and then later add the document to a collection while metadata merging is disabled, the permissions will be reset to default document permissions. In order to preserve the pre-existing permissions, you must specify them explicitly in your update.
Metadata merging is controlled by the update-policy
instance configuration property. The default value is merge-metadata
.
To disable metadata merging, set update-policy
to overwrite-metadata
using the procedure described in Configuring Instance Properties. For example:
$ cat props.xml <properties xmlns="http://marklogic.com/rest-api"> <update-policy>overwrite-metadata</update-policy> </properties> # Windows users, see Modifying the Example Commands for Windows $ curl --anyauth --user user:password -X PUT -d@"./props.xml" \ -H "Content-type: application/xml" \ http://localhost:8000/LATEST/config/properties
The equivalent JSON input is shown below:
{ "update-policy" : "overwrite-metadata" }