---
title: "Reports"
description: "Generate detailed reports and exports using Cloud CMS. Produce CSV, PDF, or ZIP files from object collections. (Gitana 4.0)"
product: "Gitana"
version: "4.0"
url: "/documentation/gitana/4.0/engine/nodes/reports"
---

# Reports

All of the objects that you place into Cloud CMS can be operated against to produce exports that consist of consolidated or reported information. You can use this capability to generate reports in CSV (comma-separated value) format as well as merged PDFs and ZIP archives.

Exports are generated from collections of objects. These objects might be collected by hand or they might consist of results sets from a document list, search page or report record set. The Cloud CMS user interface provides methods for generating these collections and exporting them to a variety of formats.

Exported results can be downloaded, emailed or stored within Cloud CMS as a newly-created document.

An export essentially consists of the following steps:

1.  Start the Export. When an export is started, it is given a configuration that describes what to export and how to package up the results. The export itself runs as a background job. An `exportId` is made available to identify the export in the future to determine its availability.
    
2.  Wait for the Export to Finish. Status checks are made using the `exportId` from the previous step.
    
3.  Do something with the Export's files. Something acquires or operates against the results of the export. For example, you might fetch the resulting ZIP document using its `exportId`. Or you might email the contents to a friend as an email attachment.
    

## Export Configuration

The export configuration tells the export process what to work on and how to package up the results.

### Common Properties

| name | type | required | description |
| --- | --- | --- | --- |
| references | array | true | an array of reference strings for objects to be exported |
| package | string | false | how to package results (either "CSV", "PDF", or "ZIP" - default is "ZIP") |
| includeMetadata | boolean | false | Whether to include JSON of objects in report generation |
| includeAttachments | boolean | false | Whether to include attachments of objects in report generation |
| includeAttachmentIds | array | false | The string IDs of any attachments to be included |
| fields | array | false | The dot-delimited string identifiers for any fields to include |

The only required property is the `references` array which identifies which objects should be exported. Objects are specified as references which generally follow the format:

```
{type}://{platformId}/{datastoreId}/{objectId}
```

If `includeAttachmentIds` is not specified, the "default" attachment will be exported. Typically, this is what you will want. However, in some cases, you may want to export other attachment IDs or multiple attachments per document.

If `fields` is not specified, all JSON fields will be included in the export.

### CSV Exports

For CSV exports, no additional properties are required. The CSV export will automatically parse the property IDs for each of the objects in your export and construct columns that are the union of properties across all objects. Object properties are then placed into rows within the CSV export.

CSV exports do not support attachments. Thus, the `includeAttachments` and `includeAttachmentIds` properties have no effect for this package type.

### PDF Exports

For PDF exports, you can elect to have Cloud CMS auto-generate your PDFs using its built-in transformer subsystem or you can specify a PDF generation template to use to customize the PDF build. You can also elect to merge generated PDFs together (for multiple objects) into a single PDF output.

| name | type | required | description |
| --- | --- | --- | --- |
| pdfTemplateRepositoryId | string | false | ID of the repository containing the PDF template |
| pdfTemplateBranchId | string | false | ID of the branch containing the PDF template |
| pdfTemplateNodeId | string | false | ID of the node for the PDF template |
| mergePdfs | boolean | false | Whether to merge PDF entries into a single PDF |

To specify a PDF generation template, use the `pdfTemplateRepositoryId`, `pdfTemplateBranchId` and `pdfTemplateNodeId` properties to point to the Cloud CMS document (or node) that contains your PDF generation template.

You can specify PDF generation templates using Freemarker, Handlebars and/or Markdown. You can also use .docx files to generate PDFs using MERGE fields.

Use the `mergePdfs` property to tell the exporter to merge all of the generated PDFs together into a single document. In this case, if you're using a PDF generation template, it will be run once with the full object set for all objects at the same time.

### ZIP Exports

For ZIP exports, you can have the exporter convert your ZIP entry files to PDF before zipping.

| name | type | required | description |
| --- | --- | --- | --- |
| zipUsePdfEntries | boolean | false | whether to convert ZIP entries to PDF before zipping |

By default, the entries of the ZIP file are not converted to PDF. The raw assets are zipped up, untouched.

## Exporting

You can run an export like this:

```
// the platform
var platform = ...;

// assume we have a collection or result map of nodes
var nodes = ...;

// export a single PDF of all of the attachments
platform.runExport(nodes, {
    "package": "PDF",
    "mergePdfs": true,
    "includeMetadata": false,
    "includeAttachments": true
}, function(exportId, status) {

    // we now have the exportId!

});
```

This kicks off the export and waits for it to complete. Once it completes, the `exportId` is given to you along with the status of the export.

Now that the export has completed, you can do things with the exported files.

### Download the Export files

The export files can be accessed using simple URLs.

If the exported file is a single file, you fetch it like this:

```
/ref/exports/{exportId}/download
```

Or if the export produced multiple files, you fetch them like this:

```
/ref/exports/{exportId}/download/0
/ref/exports/{exportId}/download/1
...
/ref/exports/{exportId}/download/9
```

For any of these calls, you can also specify the download to come at you with the "Content-Disposition" header flipped on. This allows the files to be saved instead of opened within the browser. Just add the following:

```
?a=true&filename=<filename>
```

### Email the Export files

You email the files from a completed export like this:

```
// the export ID from an export that has completed
var exportId = ...;

// assume you have an email provider
var emailProvider = ...;

// email configuration
var emailConfig = {
    "to": "eddie@vanhalen.com",
    "from": "steve@vai.com",
    //"cc": "",
    "subject": "When is the new album coming out?",
    "body": "Keep on rocking"
};

emailProvider.sendForExport(exportId, emailConfig, function() {

    // all done!

});
```

### Create a new Document from the Export files

You create a new document from a completed export's files like this:

```
// the export ID from an export that has completed
var exportId = ...;

// assume you have a branch
var branch = ...;

var exportConfig = {
    "properties": {
        "title": "Hello World"
    },
    "extraInfo": {
        "parentFolder": "/folder1/folder2"
    }
};

this.createForExport(exportId, exportConfig, function(response) {

    // all done!

});
```

## Examples

Here are a few code examples that work end-to-end:

### Search, Export and Download a CSV

```
// assume we have a branch
var branch = ...;

// assume we have a platform
var platform = ...;

branch.then(function() {

    // search for nodes
    var nodes;
    this.search("test").then(function() {
        nodes = this;
    });

    // export the nodes
    var exportId;
    this.subchain(platform).runExport(nodes, {
        "package": "CSV",
        "includeMetadata": true
    }, function(_exportId, _status) {
        exportId = _exportId;
    });

    // download the CSV
    // create node for export result
    this.then(function() {

        window.location.href = "/ref/exports/" + exportId + "/download?a=true&download=export.csv";

    });
});
```

### Query, Export and Email a PDF

```
// assume we have a branch
var branch = ...;

// assume we have a platform
var platform = ...;

// assume we have an email provider
var emailProvider = ...;

branch.then(function() {

    // search for nodes
    var nodes;
    this.query({
        "rating": {
            "$gt": 3
        }
    }).then(function() {
        nodes = this;
    });

    // export the nodes
    var exportId;
    this.subchain(platform).runExport(nodes, {
        "package": "ZIP",
        "includeAttachments": true
    }, function(_exportId, _status) {
        exportId = _exportId;
    });

    // create node for export result
    this.then(function() {

        // email configuration
        var emailConfig = {
            "to": "joe@customer.com",
            "from": "sales@company.com",
            //"cc": "",
            "subject": "Your Product Information",
            "body": "Here is the product information you requested"
        };

        this.subchain(emailProvider).sendForExport(exportId, emailConfig, function() {

            // all done!

        });

    });

});
```

### Find, Export and Create a ZIP

```
// assume we have a branch
var branch = ...;

// assume we have a platform
var platform = ...;

branch.then(function() {

    // search for nodes
    var nodes;
    this.find({
        "query": {
            "size": {
                "$in": ["sm", "md", "lg", "xl"]
            },
            "neck": {
                "$in": [16, 16.5, 17, 17.5]
            },
            "color": "green"
        },
        "search": "awesome"
    }).then(function() {
        nodes = this;
    });

    // export the nodes
    var exportId;
    this.subchain(platform).runExport(nodes, {
        "package": "ZIP",
        "zipUsePdfEntries": true,
        "includeAttachments": true
    }, function(_exportId, _status) {
        exportId = _exportId;
    });

    // create node for export result
    this.then(function() {
        var exportConfig = {
            "properties": {
                "title": "Any Size, Standard Neck, Green and Awesome!"
            },
            "extraInfo": {
                "parentFolder": "/users/user1/searches"
            }
        };
        this.createForExport(exportId, exportConfig, function(response) {

            // get the created node ID
            var id = response.rows[0]._doc;

            console.log("Created node ID is: " + id);
        });
    });
});
```

### Export an Article as a PDF document

Suppose you have a content type called `custom:article` with the following schema:

```
{
    "title": "Custom Article",
    "type": "object",
    "properties": {
        "title": {
            "type": "string",
            "title": "Title"
        },
        "body": {
            "type": "string",
            "title": "Body"
        },
        "author": {
            "type": "object",
            "properties": {
                "firstName": {
                    "type": "string",
                    "title": "First Name"
                },
                "lastName": {
                    "type": "string",
                    "title": "Last Name"
                },
                "email": {
                    "type": "string",
                    "title": "Email"
                }
            }
        }
    }
}
```

And let's imagine you have a content instance like this:

```
{
    "title": "Review of Star Trek II: The Wrath of Khan",
    "body": "An amazing film with a steady pace and intriguing storyline.",
    "author": {
        "firstName": "Opinionated",
        "lastName": "Critic",
        "email": "blah@blah.com"
    }
}
```

Let's generate a PDF for this content item. We can do so by creating another node (in this case, of type `n:pdf_template`). This node doesn't need to have anything on it in terms of JSON or metadata, but it should have an attachment which will hold our PDF template. Set the attachment mimetype to `application/freemarker` and enter the following:

```
<#assign article=objects[0]>
<div class="container">
    <div class="row">
        <div class="col-12">

            <h2>${article.title}</h2>
            <p>
                By ${article.author.firstName} ${article.author.lastName}
            </p>
            <p>
                ${article.body}
            </p>

            <h3>Summary</h3>
            <table class="table table-bordered">
                <tbody>
                <#list article.highlights as highlight>
                <tr>
                    <td><b>${highlight.key}</b></td>
                    <td>${highlight.value}</td>
                </tr>
                </#list>
                </tbody>
            </table>
            <p>
                To learn more about this article, please
                <a href="https://www.mycompany.com" title="Our Web Site">visit our web site</a>.
            </p>
        </div>
    </div>
</div>
```

We can then tie everything together like this:

```
// assume we have a platform
var platform = ...;

// this is our PDF template node
var pdfTemplate = ...;

// this is the node we want to convert to pdf
var node = ...;

platform.then(function() {

    // export the nodes
    this.runExport([node], {
        "package": "PDF",
        "includeAttachments": true,
        "pdfTemplateRepositoryId": pdfTemplate.getRepositoryId(),
        "pdfTemplateBranchId": pdfTemplate.getBranchId(),
        "pdfTemplateNodeId": pdfTemplate.getId(),
        "mergePdfs": true
    }, function(exportId, status) {

        // redirect to our generated PDF
        window.location.href = "/proxy/ref/exports/" + exportId + "/download?a=true&download=export.pdf";
    });

});
```

The PDF template is given a model which consists of root-level `objects`. Each object is a node that we pass in to the PDF template processor.

## Controlling the Merge Sequence

If you set `mergePdfs` to `true`, then all of the nodes will be passed into a single PDF generation process and a single PDF will be produced. If some of your nodes have attachments (such as Word documents or other PDF documents) that you'd like be included as part of the merge, you can do so by specifying the `mergePdfsSequence`.

The `mergePdfsSequence` array consists of string values which are references to nodes within Cloud CMS. Node references take the structure:

```
node://<platformId>/<repositoryId>/<branchId>/<nodeId>
```

You can also use the special marker `pdf` to indicate where the merged PDF should be inserted.

Here is an example where we generate a PDF and then merge two additional PDFs into it (one in the front and one in the back):

```
// assume we have a platform
var platform = ...;

// this is our PDF template node
var pdfTemplate = ...;

// this is the node we want to convert to pdf
var node = ...;

// front page PDF node
var frontPagePdfNode = ...;

// back page PDF node
var backPagePdfNode = ...;

platform.then(function() {

    // export the nodes
    this.runExport([node], {
        "package": "PDF",
        "includeAttachments": true,
        "pdfTemplateRepositoryId": pdfTemplate.getRepositoryId(),
        "pdfTemplateBranchId": pdfTemplate.getBranchId(),
        "pdfTemplateNodeId": pdfTemplate.getId(),
        "mergePdfs": true,
        "mergePdfsSequence": [
            frontPagePdfNode.ref(),
            "pdf",
            backPagePdfNode.ref()
        ]
    }, function(exportId, status) {

        // redirect to our generated PDF
        window.location.href = "/proxy/ref/exports/" + exportId + "/download?a=true&download=export.pdf";

    });

});
```
