Loading TOC...
Temporal Developer's Guide (PDF)

MarkLogic Server 11.0 Product Documentation
Temporal Developer's Guide
— Chapter 2

Quick Start

You can configure MarkLogic Server to manage and query temporal data.

This chapter walks you through the procedures for configuring the Documents database to store temporal documents and for inserting and querying temporal documents. The following are the main sections:

Create Metadata Fields for the Valid and System Axes

The valid and system axis each make use of metadata fields that define the start and end times. For example, the following query creates the metadata fields to be used to store the valid and system axes.

JavaScript Example:

var admin = require("/MarkLogic/admin.xqy");
var config = admin.getConfiguration();
var dbid = xdmp.database("Documents");
var validStart = admin.databaseMetadataField("validStart");
var validEnd = admin.databaseMetadataField("validEnd");
var systemStart = admin.databaseMetadataField("systemStart");
var systemEnd = admin.databaseMetadataField("systemEnd");
config = admin.databaseAddField(config, dbid, validStart);
config = admin.databaseAddField(config, dbid, validEnd);
config = admin.databaseAddField(config, dbid, systemStart);
config = admin.databaseAddField(config, dbid, systemEnd);
admin.saveConfiguration(config);

XQuery Example:

xquery version "1.0-ml";
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";

let $config := admin:get-configuration()
let $dbid := xdmp:database("Documents")
let $fieldspec1 := admin:database-metadata-field("validStart")
let $fieldspec2 := admin:database-metadata-field("validEnd")
let $fieldspec3 := admin:database-metadata-field("systemStart")
let $fieldspec4 := admin:database-metadata-field("systemEnd")
for $fieldspec in ($fieldspec1, $fieldspec2, $fieldspec3, $fieldspec4)
let $new-config := admin:database-add-field($config, $dbid, $fieldspec)
return admin:save-configuration($new-config)

Create Range Field Indexes for the Valid and System Axes

The valid and system axis each make use of dateTime range field indexes that define the start and end times. For example, the following query creates the field range indexes to be used to create the valid and system axes.

JavaScript Example:

var admin = require("/MarkLogic/admin.xqy");
var config = admin.getConfiguration();
var dbid = xdmp.database("Documents");
var validStart = admin.databaseRangeFieldIndex(
    "dateTime", "validStart", "", fn.true() );
var validEnd   = admin.databaseRangeFieldIndex(
    "dateTime", "validEnd", "", fn.true() );
var systemStart = admin.databaseRangeFieldIndex(
    "dateTime", "systemStart", "", fn.true() );
var systemEnd   = admin.databaseRangeFieldIndex(
    "dateTime", "systemEnd", "", fn.true() );
config = admin.databaseAddRangeFieldIndex(config, dbid, validStart);
config = admin.databaseAddRangeFieldIndex(config, dbid, validEnd);
config = admin.databaseAddRangeFieldIndex(config, dbid, systemStart);
config = admin.databaseAddRangeFieldIndex(config, dbid, systemEnd);
admin.saveConfiguration(config);

XQuery Example:

xquery version "1.0-ml";
import module namespace admin = "http://marklogic.com/xdmp/admin" 
    at "/MarkLogic/admin.xqy";
let $config := admin:get-configuration()
let $dbid := xdmp:database("Documents")
let $rangespec1 := admin:database-range-field-index(
                    "dateTime", "validStart", "", fn:true() )
let $rangespec2 := admin:database-range-field-index(
                    "dateTime", "validEnd", "", fn:true() )
let $rangespec3 := admin:database-range-field-index(
                    "dateTime", "systemStart", "", fn:true() )
let $rangespec4 := admin:database-range-field-index(
                    "dateTime", "systemEnd", "", fn:true() )
for $rangespec in ($rangespec1, $rangespec2, $rangespec3, $rangespec4)
let $new-config := admin:database-add-range-field-index(
                    $config, $dbid, $rangespec)
return admin:save-configuration($new-config)

Create System and Valid Axes

On the Documents database, create two axes, named valid and system, each to serve as a container for a named pair of field range indexes.

JavaScript Example:

var temporal = require("/MarkLogic/temporal.xqy");
var validResult = temporal.axisCreate(
    "valid", 
    cts.fieldReference("validStart", "type=dateTime"), 
    cts.fieldReference("validEnd", "type=dateTime"));
var systemResult = temporal.axisCreate(
    "system", 
    cts.fieldReference("systemStart", "type=dateTime"), 
    cts.fieldReference("systemEnd", "type=dateTime"));

XQuery Example:

xquery version "1.0-ml"; 
import module namespace temporal = "http://marklogic.com/xdmp/temporal" 
    at "/MarkLogic/temporal.xqy";
temporal:axis-create(
    "valid",
    cts:field-reference("validStart", "type=dateTime"),
    cts:field-reference("validEnd", "type=dateTime"));
xquery version "1.0-ml"; 
import module namespace temporal = "http://marklogic.com/xdmp/temporal" 
    at "/MarkLogic/temporal.xqy";
temporal:axis-create(
    "system",
    cts:field-reference("systemStart", "type=dateTime"),
    cts:field-reference("systemEnd", "type=dateTime"))

Create a Temporal Collection

Create a temporal collection, named kool, that uses the previously created system and valid axes.

JavaScript Example:

var temporal = require("/MarkLogic/temporal.xqy");
var collectionResult = temporal.collectionCreate(
"kool", "system", "valid");

XQuery Example:

xquery version "1.0-ml";
import module namespace temporal = "http://marklogic.com/xdmp/temporal" 
     at "/MarkLogic/temporal.xqy";
temporal:collection-create("kool", "system", "valid")

Axis and temporal collection names are case-sensitive.

Insert Some Temporal Documents

Insert some documents into the temporal collection. In this example, a stock trader, John, places an order to buy some stock. The record of the trade is stored as a bi-temporal document, as follows:

  1. The stock of KoolCo is trading around $12.65. John places a limit order to buy 100 shares of the stock for $12 at 11:00:00 on 3-Apr-2014 (this is the valid start time). The document for the transaction is recorded in the broker's database at 11:00:01 on 3-Apr-2014 (this is the system start time).

    JavaScript Example:

    declareUpdate();
    var temporal = require("/MarkLogic/temporal.xqy");
    var root =
        {"tempdoc": 
           {"trader": "John",
            "price": 12}
        };
    var options =
        {metadata:
           {validStart: "2014-04-03T11:00:00",
            validEnd: "9999-12-31T11:59:59Z"}
        };
    temporal.documentInsert("kool", "koolorder.json", root, options);

    XQuery Example:

    xquery version "1.0-ml";
    import module namespace temporal = "http://marklogic.com/xdmp/temporal" 
        at "/MarkLogic/temporal.xqy";   
    let $root :=   
    <tempdoc>
        <trader>John</trader> 
        <content>12</content>  
    </tempdoc>
    let $options :=  
    <options xmlns="xdmp:document-insert">
        <metadata>
           <map:map xmlns:map="http://marklogic.com/xdmp/map">
             <map:entry key="validStart">
               <map:value>2014-04-03T11:00:00</map:value>
             </map:entry>
             <map:entry key="validEnd">
               <map:value>9999-12-31T11:59:59Z</map:value>
             </map:entry> 
           </map:map>
        </metadata> 
    </options> 
    return 
    temporal:document-insert("kool", "koolorder.xml", $root, $options)

    You can use xdmp.documentGetMetadata to display the metadata for a temporal document. For example: xdmp.documentGetMetadata("koolorder.json")

  2. At 11:30:00, John changes his order to buy the stock at $13. The change is recorded as another version in the broker's database at 11:30:01.

    JavaScript Example:

    declareUpdate();
    var temporal = require("/MarkLogic/temporal.xqy");
    var root =
        {"tempdoc": 
           {"trader": "John",
            "price": "13"}
        };
    var options =
        {metadata:
           {validStart: "2014-04-03T11:30:00",
            validEnd: "9999-12-31T11:59:59Z"}
        };
    temporal.documentInsert("kool", "koolorder.json", root, options);

    XQuery Example:

    xquery version "1.0-ml";
    import module namespace temporal = "http://marklogic.com/xdmp/temporal" 
        at "/MarkLogic/temporal.xqy";   
    let $root :=   
    <tempdoc>
        <trader>John</trader> 
        <content>13</content>  
    </tempdoc>
    let $options :=  
    <options xmlns="xdmp:document-insert">
        <metadata>
           <map:map xmlns:map="http://marklogic.com/xdmp/map">
             <map:entry key="validStart">
               <map:value>2014-04-03T11:30:00</map:value>
             </map:entry>
             <map:entry key="validEnd">
               <map:value>9999-12-31T11:59:59Z</map:value>
             </map:entry> 
           </map:map>
        </metadata> 
    </options> 
    return 
    temporal:document-insert("kool", "koolorder.xml", $root, $options)

    The result should be three documents with valid and system times as shown in the graphic below. Note that the second query resulted in a split on the Original document that resulted in a split document, as well as Version 2 that contains the new content.

Run some Search Queries on the Temporal Documents

The following query searches the temporal documents, using the cts:period-range-query function to locate the documents that were in the database between 11:10 and 11:15. ISO_CONTAINS is one of the comparison operators described in ISO SQL 2011 Operators.

In this example, only the Original Document meets the search criteria.

JavaScript Example:

cts.search(cts.periodRangeQuery(
    "system",
    "ISO_CONTAINS",
    cts.period(xs.dateTime("2014-04-03T11:10:00"),
               xs.dateTime("2014-04-03T11:15:00")) ));

XQuery Example:

xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
    "system",
    "ISO_CONTAINS",
    cts:period(xs:dateTime("2014-04-03T11:10:00"),
               xs:dateTime("2014-04-03T11:15:00")) ))

The following query searches the temporal documents, using the cts:period-range-query function to locate the documents that have a valid time period that starts after 10:30 and ends at 11:30. ALN_FINISHES is one of the comparison operators described in Allen Operators.

In this example, only the Split document meets the search criteria.

JavaScript Example:

cts.search(cts.periodRangeQuery(
    "valid",
    "ALN_FINISHES",
    cts.period(xs.dateTime("2014-04-03T10:30:00"),
               xs.dateTime("2014-04-03T11:30:00")) ));

XQuery Example:

xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
   "valid",
   "ALN_FINISHES",
   cts:period(xs:dateTime("2014-04-03T10:30:00"),
              xs:dateTime("2014-04-03T11:30:00")) ))

The following query searches the temporal documents, using the cts:period-range-query function to locate the documents that were in the database after 11:20. ALN_AFTER is one of the comparison operators described in Allen Operators.

In this example, both the Split and Version 2 documents meet the search criteria.

JavaScript Example:

cts.search(cts.periodRangeQuery(
    "system",
    "ALN_AFTER",
    cts.period(xs.dateTime("2014-04-03T11:00:00"),
               xs.dateTime("2014-04-03T11:20:00")) ));

XQuery Example:

xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
   "system",
   "ALN_AFTER",
   cts:period(xs:dateTime("2014-04-03T11:00:00"),
              xs:dateTime("2014-04-03T11:20:00")) ))

The following query searches the temporal documents, using the cts:period-compare-query function to locate the documents that were in the database when the valid time period is within the system time period. ISO_CONTAINS is one of the comparison operators described in ISO SQL 2011 Operators.

In this example, only Version 2 meets the search criteria.

JavaScript Example:

cts.search(cts.periodCompareQuery(
    "system",
    "ISO_CONTAINS",
     "valid" ))

XQuery Example:

xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-compare-query(
   "system",
   "ISO_CONTAINS",
   "valid" ))

The following query uses the cts:and-query to AND two cts:collection-query functions to return the temporal document that is in the URI collection, koolorder.xml, and the latest collection.

In this example, Ver2 meets the search criteria.

JavaScript Example:

cts.search(cts.andQuery([
    cts.collectionQuery("koolorder.json"),
    cts.collectionQuery("latest")]))

XQuery Example:

xquery version "1.0-ml";
cts:search(fn:doc(), cts:and-query((
    cts:collection-query(("koolorder.xml")),
    cts:collection-query(("latest")))))

« Previous chapter
Next chapter »