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 theRequest
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 thequery
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 < 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.