Reputation: 31
I have multiple documents in MarkLogic, all belong to the same collection. I have created a template so that a view will be created and the documents records can be queried via that view. However, MarkLogic support query over views only via SQL or OpticAPI. I want to query the view via REST API. How is that possible?
Let's say my documents are on the path /employee//UUID.json.
Here is how one document was created and what data it contains:
declareUpdate();
xdmp.documentInsert("/employee/1586502/981723ioewqhdijsaduih3q8yeuiqwhdeqw.json",
{
"EmployeeID": "1234567",
"EmployeeName": "Lorem Ipsum",
"JoiningDate": "2018-07-01"
},
xdmp.defaultPermissions(),
[
"EmployeeRecordCollection"
])
Below is the template definition:
'use strict'
var tde = require("/MarkLogic/tde.xqy");
var EmployeeRecordTDE = xdmp.toJSON(
{
"template": {
"context": "/",
"collections": ["EmployeeRecordCollection"],
"rows": [
{
"schemaName": "employees",
"viewName": "EmployeeRecordView",
"columns": [
{
"name": "employeeId",
"scalarType": "string",
"val": "EmployeeID"
},
{
"name": "rateType",
"scalarType": "string",
"val": "EmployeeName",
},
{
"name": "startDate",
"scalarType": "string",
"val": "JoiningDate"
}
]
}
]
}
}
);
tde.validate(
[EmployeeRecordTDE]
);
tde.nodeDataExtract(
[fn.collection(["EmployeeRecordCollection"])],
[EmployeeRecordTDE]
);
tde.templateInsert(
"/employee/EmployeeRecordTDE.json" ,
EmployeeRecordTDE,
xdmp.defaultPermissions(),
["EmployeeRecordCollection"]
)
The above template creates a view with name "EmployeeRecordView" which can be queried using SQL as :
select * from EmployeeRecordView where...;
It can be converted into a plan using OpticAPI in Javascript as :
declareUpdate();
const op = require('/MarkLogic/optic');
const EmployeePlanSQL =
op.fromSQL("select * from EmployeeRecordView")
const planObj = EmployeePlanSQL.export();
xdmp.documentInsert("emplRatePlanSQL.json", planObj);
op.import(cts.doc('emplRatePlanSQL.json').toObject())
.result();
I thought may be I can use this plan to expose a REST API in MarkLogic so that I don't have keep queries in my application code. MarkLogic does provide a way for that BUT the entire plan definition has to be passed as query in the REST API which is again not desired.
http://localhost:8040/v1/rows?plan=...
Also, the big desire is not to keep the queries in the application code. Is there a way to expose this plan as REST API via JS function in MarkLogic or some other approach?
Upvotes: 0
Views: 276
Reputation: 31
I used REST API Extension to achieve this as I wanted to avoid middle tier.
This is the URL I hit
http://localhost:8040/LATEST/config/resources/employees?version=1.0&provider=yourTeam&method=get
with the HTTP header:
Content-Type: application/vnd.marklogic-javascript
with the following body:
function get(context, params) {
context.outputStatus = [201, 'Yay'];
const op = require('/MarkLogic/optic');
return op.import(cts.doc('emplRatePlanSQL.json').toObject()).result();
}
// Include an export for each method supported by your extension.
exports.GET = get;
The output, however, is not formatted as JSON array of records. This saves me avoid middle-tier altogether and saves a lot of Java code.
I can now invoke this plan just by calling this URI (HTTP GET):
http://localhost:8040/LATEST/resources/employees
Thanks for the help!
Upvotes: 0
Reputation: 7335
In an earlier answer, I didn't absorb that the goal is to encapsulate the query and only pass in the criteria.
If the middle tier is written in Java, one approach is to define a data Service that takes the criteria for the plan and encapsulate the query within the endpoint:
http://docs.marklogic.com/guide/java/DataServices
Otherwise, you can use a resource service extension that encapsulates the query:
http://docs.marklogic.com/guide/rest-dev/extensions#id_59188
Both the Java API and Node.js APIs provide an interface to resource service extensions. They are also callable over REST:
http://docs.marklogic.com/REST/client/service-extension
Hoping that's more useful,
Upvotes: 0