Loading TOC...
JavaScript Reference Guide (PDF)

JavaScript Reference Guide — Chapter 3

JavaScript Functions and Constructors

This chapter describes how to use the MarkLogic built-in functions, and describes how to import and use XQuery libraries in your JavaScript program. It includes the following sections:

Built-In JavaScript Functions

MarkLogic contains many built-in functions that offer fast and convenient programmatic access to MarkLogic functionality. The built-in functions are available as JavaScript functions without the need to import or require any libraries (that is why they are called built-in). You can find the functions in the Server-Side JavaScript API Documentation.

The functions are available via the following global objects:

  • cts.
  • fn.
  • math.
  • rdf.
  • sc.
  • sem.
  • spell.
  • sql.
  • xdmp.

for example, to get the current time, you can call the following:

fn.currentDateTime();

Functions That are part of the Global Object

There are MarkLogic-specific functions that are part of the global JavaScript object (without a namespace prefix). This section calls out the following global functions:

declareUpdate Function

In order to perform an update to a document, you must declare the transaction as an update; if declareUpdate is not called at the beginning of a statement, the statement is run as a query. The following is the syntax of the declareUpdate function (see Global-Object.declareUpdate):

declareUpdate(Object options) 

where options is an optional argument as follows:

{explicitCommit: true/false}

If the options argument is omitted or explicitCommit property is set to false, the transaction is automatically committed. If the explicitCommit property is set to true, then it starts a multi-statement transaction and requires an explicit xdmp.commit or xdmp.rollback to complete the transaction.

For details on transactions, see Understanding Transactions in MarkLogic Server in the Application Developer's Guide.

The following is an example of an update transaction in JavaScript:

declareUpdate();
const myDoc = {"foo":"bar"};
xdmp.documentInsert("/myDoc.json", myDoc);
// creates the /myDoc.json document

The following runs as a multi-statement transaction (although this transaction only has a single statement):

declareUpdate({explicitCommit: true});
const myDoc = {"foo":"bar"};
xdmp.documentInsert("/myDoc.json", myDoc);
xdmp.commit();
// creates the /myDoc.json document

require Function

The require function (see Global-Object.require) is available in the global object, and it allows you to import a library into your JavaScript program. For details, see require Function.

Using XQuery Functions and Variables in JavaScript

You can import XQuery library modules into a Server-Side JavaScript program and then call those functions and/or variables from JavaScript. Importing XQuery libraries is useful if you have existing XQuery code that you want to use in your JavaScript programs, and it is also useful if you want to perform a task that is well-suited to XQuery from your JavaScript Program. This section describes how to use XQuery modules with your JavaScript programs and includes the following parts:

require Function

You can import an XQuery or JavaScript library by using the following JavaScript function:

require(String location)

where location is the path to the JavaScript or XQuery file. The extension of the path can be omitted for simplicity. The path obeys the same rules for XQuery defined in Rules for Resolving Import, Invoke, and Spawn Paths in the Application Developer's Guide.

Typically, the require function is the first line of the JavaScript program, and a program can have 0 or more require functions. When importing an XQuery library, a common practice is to name your JavaScript variable as you would name your namespace prefix. For example, if you are importing the Search API library, your require statement might look as follows:

const search = require("/MarkLogic/appservices/search/search.xqy");
search.search("hello");
// returns a search response for documents matching "hello"

Importing XQuery Modules to JavaScript Programs

MarkLogic has a rich set of XQuery library modules to make it easy to write programs to do a variety of things, such as building a search application, building an alerting application, adding spelling correction to your application, and so on. You might have created your own rich sets of XQuery libraries. There might be something (such as an XPath statement) that is convenient to write in XQuery but might be less convenient to write in JavaScript.

You can make use of these XQuery libraries in MarkLogic Server-Side JavaScript programs by using the require function. This section describes the mapping of names and types from an XQuery environment to a JavaScript environment and includes the following parts:

Mapping Between XQuery Function and Variable Names to JavaScript

In XQuery, it is common to create function and variable names with hyphens (-) in them; in JavaScript, a hyphen (-) is a subtraction operator, so the names are not compatible. In JavaScript, camelCase is a common way to name functions and variables. To deal with these differences between the languages, any XQuery function or variable imported to a JavaScript program with the require function is accessible according to the following rules:

  • Namespace prefixes, which in XQuery are followed by a colon (:) and then the function local name, are denoted by the namespace prefix followed by a period (.), like any object notation.
  • Function or variable names that have hyphen characters (-) are converted to camelCase names. For example, a function in XQuery named my-function is available to JavaScript with the name myFunction.
  • For cases where the above rules might cause some ambiguity (these cases are rare), you can also access a function by its bracket notation, using the literal names from the XQuery function or variable. For example, an XQuery function names hello:my-world (that is, a function bound to the hello prefix with the local name my-world) can be accessed with the following JavaScript notation: hello["my-world"]().

You can use these rules to access any public XQuery function or variable from your JavaScript program.

Type Mapping Between XQuery and JavaScript

JavaScript has looser typing rules that XQuery, and also has fewer types than XQuery. MarkLogic automatically maps types from XQuery to JavaScript. The following table shows how XQuery types are mapped to JavaScript types.

XQuery Type JavaScript Type Notes
xs:boolean
Boolean
 
xs:integer
Integer
 
xs:double
Number
 
xs:float
Number
 
xs:decimal
Number
If the value us greater than 9007199254740992 or the scale is less than 0, then the value is a String.
json:array
Array
 
json:object
Object
 
map:map
Object
 
xs:date
Date
Any extra precision is preserved.
xs:dateTime
Date
Any extra precision is preserved.
xs:time
String
 
empty-sequence()
null
 
item()
String
 
xs:anyURI
String
 
node()
Node
 
node()*
ValueIterator
 

Importing JavaScript Modules Into JavaScript Programs

You can use the require function to import a Server-Side JavaScript library into a Server-Side JavaScript program. When you import a JavaScript library using the require function, all of the functions and global variables in the JavaScript library are available via the exports object, which is returned by the require function. For example:

const circle = require("circle.js");
circle.area(4);
// evaluates the area function from circle.js, 
// passing 4 as its parameter

You can import JavaScript libraries with either the .js or .sjs extension (with corresponding mimetypes application/javascript and application/vnd.marklogic-javascript). You cannot, however, serve up directly from the App Server a Server-Side JavaScript module with a .js file extension; directly served modules need a .sjs extension. For more details about the require function, see require Function.

Other MarkLogic Objects Available in JavaScript

There are a number of MarkLogic objects available in JavaScript to make it easier to work with nodes and documents in JavaScript. For details on these objects, see MarkLogic JavaScript Object API.

Amps and the module.amp Function

You can create amped functions in JavaScript. An amped function is a function that evaluates with amplified privileges based on the role to which an amp is configured. Amps require a function that is in the Modules database or under the <marklogic-dir>/Modules directory, as well as a piece of configuration (the amp) in the security database. For details on amps, see Temporarily Increasing Privileges with Amps in the Security Guide. This section describes JavaScript amps and includes the following parts:

module.amp Function

The module.amp function has the following signature:

module.amp(Function namedFunction)

It must be used in an exports statement that is in a JavaScript module that is in the Modules database or is under the <marklogic-dir>/Modules directory. A sample exports statement is as follows:

exports.ampedFunctionName = module.amp(ampedFunctionName);

where ampedFunctionName is the name of the function in your library to be amped.

Use the import.meta.amp() function to amp with ES6 modules. Use the style shown in the following sample statement:

export function fileExists(filename) { 
xdmp.filesystemFileExists(filename); 
} 
export const fileExistsAmped = import.meta.amp(fileExists);

Simple JavaScript Amp Example

The following creates a JavaScript module for an amp, creates an amp to reference the module, and then calls the function from another module. The result is that the function can be run by an unprivileged user, even though the function requires privileges.

  1. Create the amp module as a file in your Modules database or under the <marklogic-dir>/Modules directory. For example, on a UNIX system, create the following file as /opt/MarkLogic/test-amp.sjs (you will need to make sure the file is readable by MarkLogic):
    // This is a simple amp module
    // It requires creating an amp to the URI of this sjs file with the
    // function name.
    
    function ampedInsert() {
    xdmp.documentInsert("/amped.json", {prop:"this was produced by an \n\
      amped function"}, [xdmp.permission("qconsole-user", "read"),
                         xdmp.permission("qconsole-user", "update")]);
    };
    
    exports.ampedInsert = module.amp(ampedInsert);
  2. Create the amp that points to this function. For example, in the Admin Interface, go to Security > Amps and select the Create tab. Then enter the name of the amp function under local name (ampedInsert), leave the namespace blank, enter the path to the JavaScript module (for example, /test-amp.sjs), select filesystem for the database, and finally assign it a role to which the function amps. For this example, sect the admin role.
  3. Now, from an App Server root, create a JavaScript module with the following contents:
    declareUpdate();
    const mod = require("/test-amp.sjs");
    mod.ampedInsert();
  4. As an unprivileged user, run the program created above. For example, if the program was saved as /space/appserver/test.sjs, and your App Server root on port 8005 is /space/appserver, then access http://localhost:8005/test.sjs.

    You can create an unprivileged user in the Admin Interface by creating a user without giving it any roles.

You can then go to Query Console and see that it created the document called /amped.json.

This example is simplified from a real-world example in two ways. First, it places the amped module under the Modules directory. The best practice is to use a modules database to store your amped function. Note that when using a modules database, you need to insert the module into that database with the needed permissions on the document. Second, the example amps to the admin role. In a real-world example, it is best practice to create a role that has the minimal privileges needed to perform the functions that users with the role require.

JavaScript Type Constructors

There are MarkLogic-specific constructors added to the JavaScript environment to allow you to construct XQuery types in JavaScript. The constructors have the same names as their XQuery counterparts, but with a dot (.) instead of a colon(:) to separate the namespace from the constructor name. For constructors that have a minus sign (-) in them, you will have to put square brackets around the local name to call it (for example, cts['complex-polygon']).

To use each constructor, pass a constructible object into the constructor. The following example shows how to use the xs.QName constructor:

fn.namespaceUriFromQName(xs.QName("xdmp:foo"))
=> http://marklogic.com/xdmp
   (because the xdmp namespace is always in scope)

The following is a list of MarkLogic constructors that you can call from JavaScript.

xs.simpleDerivationSet
xs.gYear
xs.public
xs.language
xs.short
xs.decimal
xs.reducedDerivationControl
xs.gYearMonth
xs.date
xs.double
xs.nonPositiveInteger
xs.positiveInteger
xs.blockSet
xs.normalizedString
xs.namespaceList
xs.gMonth
xs.integer
xs.int
xs.anyAtomicType
xs.gMonthDay
xs.NCName 
xs.unsignedShort
xs.derivationControl
xs.IDREFS
xs.derivationSet
xs.token
xs.ID
xs.nonNegativeInteger
xs.anyURI
xs.NMTOKEN
xs.allNNI
xs.QName
xs.base64Binary
xs.boolean
xs.long
xs.Name
xs.yearMonthDuration
xs.duration
xs.NMTOKENS
xs.dayTimeDuration
xs.negativeInteger
xs.NOTATION
xs.unsignedInt
xs.unsignedLong
xs.untypedAtomic
xs.formChoice
xs.dateTime
xs.float
xs.ENTITY
xs.byte
xs.time
xs.unsignedByte
xs.ENTITIES
xs.string
xs.IDREF
xs.hexBinary
xs.gDay
cts.andNotQuery
cts.andQuery
cts.boostQuery
cts.box
cts.circle
cts.collectionQuery
cts.collectionReference
cts.complexPolygon
cts.confidenceOrder
cts.directoryQuery
cts.documentFragmentQuery
cts.documentOrder
cts.documentQuery
cts.elementAttributePairGeospatialQuery
cts.elementAttributeRangeQuery
cts.elementAttributeReference
cts.elementAttributeValueQuery
cts.elementAttributeWordQuery
cts.elementChildGeospatialQuery
cts.elementGeospatialQuery
cts.elementPairGeospatialQuery
cts.elementQuery
cts.elementRangeQuery
cts.elementReference
cts.elementValueQuery
cts.elementWordQuery
cts.falseQuery
cts.fieldRangeQuery
cts.fieldReference
cts.fieldValueQuery
cts.fieldWordQuery
cts.fitnessOrder
cts.geospatialElementAttributePairReference
cts.geospatialElementChildReference
cts.geospatialElementPairReference
cts.geospatialElementReference
cts.geospatialJsonPropertyChildReference
cts.geospatialJsonPropertyPairReference
cts.geospatialJsonPropertyReference
cts.geospatialPathReference
cts.indexOrder
cts.jsonPropertyChildGeospatialQuery
cts.jsonPropertyGeospatialQuery
cts.jsonPropertyPairGeospatialQuery
cts.jsonPropertyRangeQuery
cts.jsonPropertyReference
cts.jsonPropertyScopeQuery
cts.jsonPropertyValueQuery
cts.jsonPropertyWordQuery
cts.linestring
cts.locksFragmentQuery
cts.longLatPoint
cts.lsqtQuery
cts.nearQuery
cts.notInQuery
cts.notQuery
cts.order
cts.orQuery
cts.pathGeospatialQuery
cts.pathRangeQuery
cts.pathReference
cts.period
cts.periodCompareQuery
cts.periodRangeQuery
cts.point
cts.polygon
cts.propertiesFragmentQuery
cts.punctuation
cts.qualityOrder
cts.query
cts.reference
cts.region
cts.registeredQuery
cts.reverseQuery
cts.scoreOrder
cts.searchOption
cts.similarQuery
cts.space
cts.special
cts.termQuery
cts.token
cts.tripleRangeQuery
cts.trueQuery
cts.unordered
cts.uriReference
cts.word
cts.wordQuery
dir.type
math.coefficients
sem.iri
sem.variable
sem.blank
« Previous chapter
Next chapter »