Exploring op.fromView()
Turn TDE and relational views into stable row plans
op.fromView() is the entry point for row-based Optic plans when your data already has a view behind it. Instead of walking documents directly, start from the TDE-backed or relational view and treat it as a row source ready for projection, filtering, and joins.
Use it when the data shape is already clear and the next step is row logic rather than document traversal. The examples below show how a simple view read becomes easier to maintain once you add explicit qualifiers and column scoping.
Llamaverse Context for This API Call
When you run op.fromView('llamaverse', 'llamas'), you are not querying arbitrary JSON directly. You are querying a TDE view that has already mapped source document content into rows and columns.
| Context Item | What this article uses |
|---|---|
| Data set | llamaverse v2.0+ sample data |
| Source documents | /cleverllamas/llamaverse/raw/wild-llamas/llamas/{uuid}.json |
| Schema | llamaverse |
| View | llamas |
| Columns used in this article | name, placeOfBirth (and later id, secretPowerId in follow-on examples) |
| Field usage | None in this specific example; this is view-column projection, not a field query |
| Index context | TDE view extraction and column metadata must be available in the target database for op.fromView() to resolve rows |
If op.fromView() returns no rows or throws a view/schema error, first confirm that llamaverse is loaded and that the TDE templates for the llamaverse.llamas view are installed in the same database your Optic query is running against.
Source Docs and Configuration Used
| Item | Value used in this article |
|---|---|
| MarkLogic API docs | op:from-view, op.fromView |
| Llamaverse source collection | wild-llamas |
| Llamaverse source URI pattern | /cleverllamas/llamaverse/raw/wild-llamas/llamas/{uuid}.json |
| Required database config | TDE templates must expose view llamaverse.llamas with columns name and placeOfBirth |
Parameters
| Name | Datatype | Required | Notes |
|---|---|---|---|
schema | String | Yes | The name of the schema that contains the view. |
view | String | Yes | The name of the view to source data from. |
qualifier | String | No | Optional runtime alias for the view name, useful when multiple sources would otherwise have ambiguous column names. |
systemCols | String | No | Optional system columns (for example fragment ID) used in join and diagnostics workflows. |
Default Usage
In this example, no qualifier or system column is used, so the plan resolves with the default view and schema naming. The simplest op.select() shape keeps the code short but becomes fragile once column names are not unique across joins.
{
"name": "Aaron",
"breed": "Huacaya",
"placeOfBirth": "Cusco, Peru",
"secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";
import module namespace op = "http://marklogic.com/optic" at "/MarkLogic/optic.xqy";
op:from-view("llamaverse", "llamas")
=> op:select(("name", "placeOfBirth"))
=> op:order-by("name")
=> op:limit(3)
=> op:result()
'use strict';
const op = require('/MarkLogic/optic');
const llamaPlan = op.fromView('llamaverse', 'llamas')
.select(['name', 'placeOfBirth'])
.orderBy('name')
.limit(3);
const results = llamaPlan.result();
({
sample: 'optic/op-fromView/assets/default-usage.sjs',
kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
count: Array.isArray(results) ? results.length : 0,
data: results
});
You can see in the results that data is scoped by schema and view name, similar to schema.table scoping in relational systems.
Explicit View and Column References
Building on the previous example, op.viewCol() lets you scope column references to a specific view. In simple plans this looks optional, but in multi-join plans it prevents ambiguity and keeps maintenance sane.
There is also op.col(), which is more generic. Prefer explicit op.viewCol() references when the plan is expected to grow.
{
"name": "Aaron",
"breed": "Huacaya",
"placeOfBirth": "Cusco, Peru",
"secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";
import module namespace op = "http://marklogic.com/optic" at "/MarkLogic/optic.xqy";
op:from-view("llamaverse", "llamas")
=> op:select((
op:view-col("llamas", "name"),
op:view-col("llamas", "placeOfBirth")
))
=> op:order-by("name")
=> op:limit(3)
=> op:result()
'use strict';
const op = require('/MarkLogic/optic');
const llamaPlan = op.fromView('llamaverse', 'llamas')
.select([op.viewCol('llamas', 'name'), op.viewCol('llamas', 'placeOfBirth')])
.orderBy('name')
.limit(3);
const results = llamaPlan.result();
({
sample: 'optic/op-fromView/assets/explicit-view-col.sjs',
kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
count: Array.isArray(results) ? results.length : 0,
data: results
});
The results are identical.
Change the View Name at runtime
If you want SQL-style aliases, use the qualifier parameter. It lets you rename the source at runtime and keeps later column references clear.
{
"name": "Aaron",
"breed": "Huacaya",
"placeOfBirth": "Cusco, Peru",
"secretPowerId": "d8839ba6-2b77-4bcc-9927-b86cdfecb9fb"
}
xquery version "1.0-ml";
import module namespace op = "http://marklogic.com/optic" at "/MarkLogic/optic.xqy";
op:from-view("llamaverse", "llamas", "llamaList")
=> op:select((
op:view-col("llamaList", "name"),
op:view-col("llamaList", "placeOfBirth")
))
=> op:order-by("name")
=> op:limit(3)
=> op:result()
'use strict';
const op = require('/MarkLogic/optic');
const llamaPlan = op.fromView('llamaverse', 'llamas', 'llamaList')
.select([op.viewCol('llamaList', 'name'), op.viewCol('llamaList', 'placeOfBirth')])
.orderBy('name')
.limit(3);
const results = llamaPlan.result();
({
sample: 'optic/op-fromView/assets/runtime-qualifier.sjs',
kind: Array.isArray(results) ? (results.every((item) => typeof item === 'object' && 'subject' in item && 'predicate' in item && 'object' in item) ? 'triples' : 'rows') : ((results !== null && typeof results === 'object') ? 'object' : 'scalar'),
count: Array.isArray(results) ? results.length : 0,
data: results
});
Now the difference is explicit: llamaList is the runtime qualifier, not llamaverse.llamas.
The next step is op.select(), where qualifier handling combines with projection patterns.
When to Choose op.fromView()
Use op.fromView() when your data is already modelled as a view and the next step is row logic, not raw document traversal.
Choose explicit qualifiers and column scoping early. That small discipline prevents ambiguous-column failures once joins and reporting logic become more complex.
- Exploring op.select() — Shape, rename, and project columns from the rows your view delivers.
- Optic Joins Starter Pack — Join views together once you understand individual source shapes.
- Optic Data Source Starter Pack — Compare all available Optic source shapes side by side.
Need Some Help?
Looking for more information on this subject or any other topic related to MarkLogic? Contact Us (info@cleverllamas.com) to find out how we can assist you with consulting or training!
- Llamaverse Context for This API Call
- Source Docs and Configuration Used
- Parameters
- Default Usage
- Explicit View and Column References
- Change the View Name at runtime
- When to Choose op.fromView()