Mayank Gupta
Mayank Gupta

Reputation: 31

Is there a way in MarkLogic to query a view via REST API without writing the code for it in middle tier?

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

Answers (2)

Mayank Gupta
Mayank Gupta

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

ehennum
ehennum

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

Related Questions