Quantcast
Channel: Nuxeo Blogs » Product & Development
Viewing all articles
Browse latest Browse all 161

Using the node.js Nuxeo Client

$
0
0

Code

Last week we were asked if there is an easy way to rename a bunch of documents, located in some specific folders, in our intranet. After manually updating a lot of main files, the documents titles were no longer synced with the main file name. The question was how to update the document title to match the main file name.

As “eating your own dog food” is quite a good thing, let’s use our own REST API and clients to do this.

I have chosen to use the node.js Nuxeo client. You can find documentation in the README on the nuxeo-js-client GitHub repository.

The full project for this blog post is available here.

Let’s see, step by step, how we can do this.

Project Initialization

First, you need to initialize your node.js project through npm init:

$ npm init

Answer all questions and you’re ready to go!

Then, add the nuxeo node module to your project:

$ npm install nuxeo

This will install the latest version of the node.js nuxeo module (at the time of writing, it’s the 0.2.0 version).

Create the Client

Create an empty file in your project, named sample.js for instance.

First, we need to require the nuxeo module so that we can use it:

var nuxeo = require('nuxeo');

From here, we can create a new Client object targeting a Nuxeo Platform server:

var client = new nuxeo.Client({
  baseURL: 'http://localhost:8080/nuxeo/',
  username: 'Administrator',
  password: 'Administrator'
});

Those are the default values, replace them with the values for your own Nuxeo Platform server.

If you don’t want to change them you can also write:

var client = new nuxeo.Client();

When you have a Client object, you can finally try to connect to the server and do something:

client.connect(function(error, client) {
  if (error) {
    console.error('Cannot connect to Nuxeo server');
    throw new Error(error);
  }

  // do stuff
});

The Query

Let’s say we want to rename all the File documents which have a main file, inside the /default-domain/workspaces/ document (recursively). We can create the following query (ignoring proxies, versions and deleted documents):

var query = "SELECT * FROM Document"
  + " WHERE ecm:primaryType = 'File'"
  + " AND ecm:path STARTSWITH '/default-domain/workspaces/'"
  + " AND content/data IS NOT NULL"
  + " AND dc:title <> content/name"
  + " AND ecm:isProxy = 0 AND ecm:isCheckedInVersion = 0"
  + " AND ecm:currentLifeCycleState != 'deleted'";

Build the Request

Now that we have our query, here is how we can build a Request object that will be executed later:

var request = client.request('/').schema(['dublincore', 'file'])
  .path('@search')
  .query({
    'query': query,
  });

Some explanations on what we use:

  • client.request('/'): actually builds the Request object on the Root document (with path ‘/’),
  • schema(['dublincore', 'file']): we will retrieve only the ‘dublincore’ and ‘file’ schemas in the returned JSON object,
  • path('@search'): append ‘@search’ to the request path (we want do to a search),
  • query(...): append the specified query parameters to the request URL (here, only the query parameter).

Execute the Request

Now that we have our request, we can execute it to retrieve the list of documents matching our query:

request.execute(function(error, data) {
  if (error) {
    console.error('Error while fetching documents');
    throw new Error(error);
  }

  // do stuff
  console.log(data);
});

Here is the JSON response of executing it on my own server, where one file needs to be renamed:

{ 'entity-type': 'documents',
  isPaginable: true,
  resultsCount: 1,
  pageSize: 50,
  maxPageSize: 100,
  currentPageSize: 1,
  currentPageIndex: 0,
  numberOfPages: 1,
  isPreviousPageAvailable: false,
  isNextPageAvailable: false,
  isLastPageAvailable: false,
  isSortable: true,
  hasError: false,
  errorMessage: null,
  totalSize: 1,
  pageIndex: 0,
  pageCount: 1,
  entries:
   [ { 'entity-type': 'document',
       repository: 'default',
       uid: '91e4bf57-bc80-4178-9604-b02ccd6cca8c',
       path: '/default-domain/workspaces/test/afile',
       type: 'File',
       state: 'project',
       versionLabel: '0.0',
       isCheckedOut: true,
       title: 'afile',
       lastModified: '2014-06-10T13:48:51.00Z',
       properties: [Object],
       facets: [Object],
       changeToken: '1402408131000',
       contextParameters: [Object] } ] }

As you can see, the results are paginated, by default with 50 documents. We will process the first page of entries, and then each subsequent page:

request.execute(function(error, data) {
  if (error) {
    console.error('Error while fetching documents');
    throw new Error(error);
  }

  // process the first page
  processEntries(data.entries);
  // iterate over all the next pages (using the currentPageIndex parameter
  // to retrieve the right page)
  for (var i = 1; i < data.pageCount; i++) {
    request.query({ currentPageIndex: i }).execute(function(error, data) {
      if (error) {
        console.error('Error while fetching documents');
        throw new Error(error);
      }

      processEntries(data.entries);
    });
  }
});

Update the Documents

Let’s see the implementation of the processEntries function:

function processEntries(entries) {
  for (var i = 0; i &lt; entries.length; i++) {
    var doc = client.document(entries[i]);
    if (doc.properties['file:content'] && doc.properties['file:content'].name
      && doc.properties['dc:title'] !== doc.properties['file:content'].name) {
      doc.set({'dc:title' : doc.properties['file:content'].name })
      doc.save(function(error, data) {
        console.log("Successfully renamed '" + data.title + '"');
      });
    }
  }
}

Here, we use the Document object abstraction over a simple JSON document to help us update the properties and save the doc. Otherwise, we would have directly updated the properties field of the JSON document, and saved it through a PUT with a Request object.

var doc = client.document(jsonDoc)

Updating the properties of a document is as easy as calling the set method on the Document object:

doc.set(propertiesObject)

Only the properties existing on the propertiesObject will be updated on the document, the properties object of the document is not completely replaced. Here we update only the title, using the dc:title property.

After updating the properties, we can now save the document on the server through the save method:

doc.save(function(error, data) {
  if (error) {
    console.error('Error while saving document');
    throw new Error(error);
  }

  console.log("Successfully renamed '" + data.title + '"');
});

Full Project

I’ve set up this full project, with more logs, comments and options, on the nuxeo-node-sample GitHub repository.

To run it, simply do:

$ git clone https://github.com/troger/nuxeo-node-sample.git
$ cd nuxeo-node-sample
$ node sample.js [--dry-run]

You can setup the client to use your own Nuxeo Platform server in the sample.js file, as well as the query you want to use to find documents.

The --dry-run option allow you to just see which files will be updated, without updating them.

The post Using the node.js Nuxeo Client appeared first on Nuxeo Blogs.


Viewing all articles
Browse latest Browse all 161

Trending Articles