Building Inline Views
- Last Updated: September 10, 2026
- 3 minute read
- MarkLogic Server
- Version 12.0
- Documentation
Virtual views are useful for supporting ad hoc queries and data exploration on large data sets where query needs are not known up front or are frequently changing. For more information about virtual views and how to access them, see Template Driven Extraction.
Inline views expand that feature by allowing the view structure to be defined at query time. So, there is no need to configure a TDE template before running the search.
fromDocs Data Access Function
Rows from TDE views are generally accessed using the fromView() data access function. Inline views are configured using the fromDocs() data access function, which has this signature:
| JavaScript | XQuery |
|---|---|
op.fromDocs( query as cts.query, contextPath as String, columns as columnDef, [viewName as String?], [systemColumn as String?], [namespaces as objectLiteral?] ) |
op:from-docs( $query as cts:query, $context-path as xs:string, $columns as $columnDef, [$view-name as xs:string?], [$system-column as xs:string?], [$namespaces as map:map?] ) |
The op.fromDocs() function documentation provides a more in-depth description of each parameter.
The rest of this section focuses on the helper object in constructing the columnDef parameter.
Column Builder
A helper function (XQuery) or object (JavaScript) is available to build the column definition parameter. The primary method is through addColumn or op:add-column, which can be chained with configuration methods such as type(), xpath(), and so on. See Sample Query for sample usage.
These column configurations, described in Columns in Relational Data Modeling with MarkLogic Server, may be adjusted using the equivalent column builder function:
| TDE column config | Column Builder Function | Column Builder default |
|---|---|---|
scalar-type |
type() |
string |
val |
xpath() or expr() |
value of input to columnBuilder.addColumn() |
collation |
collation() |
http://marklogic.com/collation/ |
dimension |
dimension() |
none |
coordinate-system |
coordinateSystem() |
none |
units |
units() |
miles |
Those functions may be chained after the call to addColumn().
This table shows how to convert a TDE column configuration into the equivalent columnDef using op:column-builder() or op.columnBuilder():
| TDE column | XQuery | Javascript |
|---|---|---|
<column> <name>basic</name> <scalar-type>string</scalar-type> <nullable>true</nullable> <val>basic</val> </column> |
op:column-builder()
=> op:add-column("basic") |
op.columnBuilder()
.addColumn("basic") |
TDE templates always use a string value for default. For column definitions defined using op:column-builder() or op.columnBuilder(), your default can be typed:
| TDE column | XQuery | Javascript |
|---|---|---|
<column> <name>count</name> <scalar-type>int</scalar-type> <default>-99</default> </column> |
op:column-builder()
=> op:add-column("count")
=> op:type("int")
=> op:nullable(fn:false())
=> op:default(-99) |
op.columnBuilder()
.addColumn("count")
.type("int")
.nullable(false)
.default(-99) |
.expr() lets you use data transformation functions:
| TDE column | XQuery | Javascript |
|---|---|---|
<column> <name>category</name> <scalar-type>string</scalar-type> <val>fn:substring(label, 1, 10)</val> </column> |
op:column-builder()
=> op:add-column("category")
=> op:nullable(fn:false())
=> op:expr(ofn:substring(label, 1, 10)) |
op.columnBuilder()
.addColumn("category")
.nullable(false)
.expr(op.fn.substring(label, 1, 10)) |
When using op:xpath() inside an op:expr() column call, make op:context() the first parameter:
| XQuery | Javascript |
|---|---|
op:column-builder()
=> op:add-column("label")
=> op:expr(op.xpath(op.context(), 'label')) |
op.columnBuilder()
.addColumn("label")
.expr(op.xpath(op.context(), 'label')) |
Subsequent columns do not have access to preceding column definitions. So, these column definitions result in columns named copyCount and doubleCount with values of null:
| XQuery | Javascript |
|---|---|
op:column-builder()
=> op:add-column("count")
=> op:xpath("quantity")
=> op:add-column("copyCount")
=> op:expr(op:xpath(op:context(), 'count'))
=> op:add-column("doubleCount")
=> op:val('count * 2') |
op.columnBuilder()
.addColumn("count")
.xpath("quantity")
.addColumn("copyCount")
.expr(op.xpath(op.context(), 'count'))
.addColumn("doubleCount")
.val('count * 2') |
op:expr() and op:xpath() cannot be defined for the same column. So, this column configuration results in an XDMP-ARG-DETAIL error:
| XQuery | Javascript |
|---|---|
op:column-builder()
=> op:add-column("label")
=> op:expr(op:xpath(op:context(), 'label'))
=> op:xpath("label") |
op.columnBuilder()
.addColumn("label")
.expr(op.xpath(op.context(), 'label'))
.xpath('label') |
Scenario Setup
This section provides a scenario to better understand the various concepts and features related to inline views.
Sample Document
Create this sample document using Query Console:
'use strict';
declareUpdate();
xdmp.documentInsert(
'/products/flipflops.json',
{
'product': {
'label': 'flip flops',
'stock': 20,
'purchase': {
'cost': 1.99,
},
'retail':{
'price': 2.49,
}
}
}
)
Sample TDE Template
If you were using TDE views, you would need a template like this to query the document:
'use strict';
declareUpdate();
const tde = require("/MarkLogic/tde.xqy");
let template = xdmp.toJSON({
"template": {
"description": "test column access",
"context": "/product",
"rows": [
{
"schemaName": "acme",
"viewName": "products",
"viewVirtual": true,
"columns": [
{
"name": "label",
"scalarType": "string",
"val": "label"
},
{
"name": "count",
"scalarType": "int",
"val": "stock"
},
{
"name": "cost",
"scalarType": "decimal",
"val": "purchase/cost"
},
{
"name": "price",
"scalarType": "decimal",
"val": "retail/price",
"nullable": true
}
]
}
]
}
})
// review the generated row data
tde.nodeDataExtract(fn.doc().toArray(),[template]);
Sample Query
But instead, run this query in Query Console to access the sample document through an inline view:
'use strict';
const op = require('/MarkLogic/optic');
op.fromDocs(
cts.trueQuery(),
"product",
op.columnBuilder()
.addColumn("label")
.addColumn("count")
.xpath("stock")
.type("int")
.addColumn("cost")
.xpath("purchase/cost")
.type("decimal")
.addColumn("price")
.xpath("retail/price")
.type("decimal")
.nullable(true)
)
.result()
Concerns and Considerations
In-line views have the same limitations as Virtual Views. These are listed as part of Concerns and Considerations in the Creating Template Views section of the Relational Data Modeling with MarkLogic Server.