<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>GoodData Developer Blog</title>
 
 <link href="http://developer.gooddata.com" />
 <updated>2012-02-27T01:09:22-08:00</updated>
 <id>http://developer.gooddata.com</id>

 
 <author>
   <name>Good Data</name>
   <email>support@gooddata.com</email>
 </author>
 
 
 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/gooddata-developer-blog" /><feedburner:info uri="gooddata-developer-blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>Updating the Variable Using REST API</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/QGaXfEaufHc/Updating-Variable-Programmatically" />
   <updated>2012-02-15T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2012/02/15/Updating-Variable-Programmatically</id>
   <content type="html">&lt;h1 id='updating_the_variable_using_rest_api'&gt;Updating the Variable Using REST API&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Do you use variables in your analytical projects quite often? If so, you surely need to update them from time to time. That means you&amp;#8217;ll definitely be interested in how to update the variable values programmatically. As in other use cases, our Platform is fully covered by REST API, so this can also be done using API resources.&lt;/p&gt;

&lt;h2 id='variable_api'&gt;Variable API&lt;/h2&gt;

&lt;p&gt;As mentioned before, we&amp;#8217;ll use our REST API with several API calls and payloads. By following the steps below, you&amp;#8217;ll be able to update variable values. A variable value can be a numeric value or a filter. A numeric variable type is simple and contains only a single value. If you create a filter variable, you will need to select an attribute value that&amp;#8217;ll define the filter. Just before we start the first API call, I would like to describe the concept of variable API. If you are not sure what the variable is, see the following &lt;a href='https://secure.gooddata.com/docs/html/reference.guide.data.variables.html'&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remember that variables were formerly called prompts, so while using GoodData API, you might see both terms being used. Every variable is represented by a prompt object that can be associated with one or multiple prompt answers. A prompt answer is a specific variable value associated with the user or the project.&lt;/p&gt;

&lt;p&gt;As you know, variables can be used in reports or metrics. In our example, we have the variable - Department - and we want to update a user specific value.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/filterVariable.png' alt='Filter Variable' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h2 id='step_1__get_the_list_of_variablesprompts'&gt;Step 1 - Get the list of variables/prompts:&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, variables were formerly known as prompts. So, if you want to get list of all variables in the project, you will use GET call as specified below:&lt;/p&gt;

&lt;p&gt;GET -&amp;gt; &lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/query/prompts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;the answer should look something like this:&lt;/p&gt;
&lt;pre&gt;
{
    "query": {
        "entries": [
            {
                "link": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/256",
                "author": "/gdc/account/profile/19765",
                "tags": "",
                "created": "2012-01-11 10:25:45",
                "deprecated": "0",
                "summary": "",
                "title": "Department",
                "category": "prompt",
                "updated": "2012-01-11 10:25:45",
                "contributor": "/gdc/account/profile/19765"
            },
            {
                ...
                ...
            }
        ],
        "meta": {
            "summary": "Metadata Query Resources for project obv8xyny3dygpb10t2rpai4tjw5nfcif",
            "title": "List of prompts",
            "category": "query"
        }
    }
}
&lt;/pre&gt;
&lt;h2 id='step_2__find_variable_id'&gt;Step 2 - Find variable ID&lt;/h2&gt;

&lt;p&gt;To update the variable value, you need to know what the variable item ID is because you&amp;#8217;ll need it in the next step. Grab the prompt URI from previous step (that uri inside the link tag) and use it to search the variable item ID in the following resource:&lt;/p&gt;

&lt;p&gt;POST -&amp;gt; &lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/variables/search&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;with following payload:&lt;/p&gt;
&lt;pre&gt;
{
    "variablesSearch": {
        "variables": [
            "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/256"
        ],
        "context": [
            
        ]
    }
}
&lt;/pre&gt;
&lt;p&gt;The API will give you the following JSON with all variable answers:&lt;/p&gt;
&lt;pre&gt;
{
    "variables": [
        {
            ...

            },
            {
            "uri": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/variables/item/4",
            "prompt": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/256",
            "related": "/gdc/projects/obv8xyny3dygpb10t2rpai4tjw5nfcif",
            "level": "project",
            "objects": [],
           "expression": "TRUE",
            "type": "filter"
        },
        {
            ...
            ...
            ...
            },
            {
            "uri": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/variables/item/8",
            "prompt": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/256",
            "related": "/gdc/account/profile/30672",
            "level": "user",
            "objects": [
                {
                    "category": "attributeElement",
                    "title": "HQ Marketing",
                    "attributeUri": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11",
                    "uri": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11/elements?id=3"
                },
                {
                    "link": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11",
                    "author": "/gdc/account/profile/19765",
                    "tags": "",
                    "created": "2012-01-23 10:11:25",
                    "deprecated": "0",
                    "summary": "",
                    "title": "Department",
                    "category": "attribute",
                    "updated": "2012-01-23 10:12:28",
                    "contributor": "/gdc/account/profile/19765"
                }
            ],
            
            "expression": "[/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11] IN ([/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11/elements?id=3])",
            "type": "filter"
            }
    ]
}
&lt;/pre&gt;
&lt;p&gt;The first part is the default variable answer and the rest of the JSON represents the user-specific variable answers. As you can see the default answer is &amp;#8220;ALL&amp;#8221; because the objects array is empty. It means the filter contains all attribute values.&lt;/p&gt;

&lt;p&gt;The expression value is what describes which attribute value belongs to the specific user. The user uri is a value of the related field.&lt;/p&gt;

&lt;h2 id='step_3__updating_the_variable_value'&gt;Step 3 - Updating the Variable value&lt;/h2&gt;

&lt;p&gt;This is the key part. From the previous step, we&amp;#8217;ve found the item ID. In our example, we would like to update the Variable value that is identified by item ID = 8. By POSTing following JSON, you&amp;#8217;ll update the variable to the new value. See the HTTP request:&lt;/p&gt;

&lt;p&gt;POST -&amp;gt; &lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/variables/item/8&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;
{ 
 "variable": { 
 "expression": "[/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11] IN ([/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11/elements?id=5], [/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11/elements?id=3], [/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/11/elements?id=7])", 
 "level": "user", 
 "type": "scalar", 
 "prompt": "/gdc/md/obv8xyny3dygpb10t2rpai4tjw5nfcif/obj/256", 
 "related": "/gdc/account/profile/30672" 
} 
}
&lt;/pre&gt;
&lt;p&gt;The structure tells us that we&amp;#8217;ll update the variable with the value that is defined by the expression. The expression is the part where you need to put the new variable value. In this case, you&amp;#8217;ll set the user related variable to the attribute values that have&lt;/p&gt;

&lt;p&gt;ID = 5,3 and 7.&lt;/p&gt;

&lt;p&gt;As you can see, you are able to set more variable options. The level specifies if the variable is set for the whole project or for a specific user. Type could have two values - scalar or filter. As you probably know, scalar is the constant number and filter is the variable that is defined by specific attribute value.&lt;/p&gt;

&lt;p&gt;Well, we&amp;#8217;ve successfully updated the filter variable value. Let us know how it works for you!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/QGaXfEaufHc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2012/02/15/Updating-Variable-Programmatically</feedburner:origLink></entry>
 
 <entry>
   <title>Determining the Attribute Value ID</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/beR50uGdOKQ/Determine-Element-ID" />
   <updated>2012-01-09T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2012/01/09/Determine-Element-ID</id>
   <content type="html">&lt;h1 id='determining_the_attribute_value_id'&gt;Determining the Attribute Value ID&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello everybody,&lt;/p&gt;

&lt;p&gt;Today we have a basic and useful tip. I would like to describe some common principles in GoodData. I would show you how and where you can find the attribute element IDs. The following workflow will help you use the GoodData REST API, especially when you create the Mandatory User Filter.&lt;/p&gt;

&lt;p&gt;For those who are new to GoodData, every object in our platform has its own unique ID. That means that you can easily call&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/obj/OBJECT_ID&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and you will get the object definition. So every report, attribute etc. has its unique ID and you can quite easily get it by calling the API. This is the first type of ID in GoodData. You probably already know how to use it.&lt;/p&gt;

&lt;p&gt;Today I would like to show you how you can identify the ID of given attribute value. Each attribute value is represented by unique ID and this ID is different to the metadata object ID.&lt;/p&gt;

&lt;p&gt;Imagine that you would like to create new &lt;a href='http://developer.gooddata.com/blog/2011/12/07/Mandatory-User-Filters/'&gt;Mandatory User Filter&lt;/a&gt;. The question is - What is the easiest way to determine the attribute value ID?&lt;/p&gt;

&lt;p&gt;You want to filter reports by a specific department (which is a project attribute) for a specific user. You know the department&amp;#8217;s name, but you are not sure about the given department (= attribute element) ID. Let&amp;#8217;s use our grey pages.&lt;/p&gt;

&lt;p&gt;The first step is well known, login to the GoodData platform using your credentials and grey pages. Go to&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/account/login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Enter the username and password. After submitting, you will receive two links, don&amp;#8217;t forget to click on one of them! This will set your Temporary Token cookie needed for authentication.&lt;/p&gt;

&lt;p&gt;Secondly, go to &lt;code&gt;https://secure.gooddata.com/gdc/md/&lt;/code&gt; where you can see all your existing projects. Select your project, click on the link, and you are in the project metadata resource. Now, go to the &lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/query/attributes&lt;/code&gt; , see the screenshot below&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/determine-id/Attribute-List.png' alt='Attribute List' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As you can see, all project attributes are listed here. Select the attribute that you want to use and click on the link again. It will bring you to the attribute description.&lt;/p&gt;

&lt;p&gt;In the picture below, the attribute object ID and URI are highlighted by red arrows and the object element&amp;#8217;s URI is highlighted by green arrows. Remember that attribute elements belong to a specific attribute display form. Keep in mind that you can set multiple display forms for one attribute.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/determine-id/Attribute-Definition.png' alt='Attribute Definition' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Now the final part. Every attribute has some values and values may differ from various display Forms. These values are called elements and every element has its unique ID. See the element description for the Department attribute in the screenshot below&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/determine-id/Element-List.png' alt='Element List' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As you can see in the screenshot above, you can easily determine the given element ID. In our example, the ID of the Human Resources Department is 4.&lt;/p&gt;

&lt;p&gt;Just before finishing I would like to show you the Mandatory User Filter expression based on what we have from the example above:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;object-id&amp;gt;]=[/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;object-id&amp;gt;/elements?id=&amp;lt;element-id&amp;gt;]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remember that attribute element ID is totally different ID than object ID (report, attribute, metric)!&lt;/p&gt;

&lt;p&gt;As you can see, it is necessary to know the attribute element ID to create new Mandatory User Filter. Read the article that will describe you the whole &lt;a href='http://developer.gooddata.com/blog/2011/12/07/Mandatory-User-Filters/'&gt;Mandatory User Filter creation process&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have a nice day!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/beR50uGdOKQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2012/01/09/Determine-Element-ID</feedburner:origLink></entry>
 
 <entry>
   <title>Export selected Report using Grey Pages</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/N-YCV6wQock/Export-Report-To-PDF" />
   <updated>2012-01-06T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2012/01/06/Export-Report-To-PDF</id>
   <content type="html">&lt;h1 id='export_selected_report_using_grey_pages'&gt;Export selected Report using Grey Pages&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi Devs!&lt;/p&gt;

&lt;p&gt;Our friends from &lt;a href='http://www.keboola.com'&gt;Keboola&lt;/a&gt; recently wrote a nice article about how they integrated the OpenBrand app with some magic in the GoodData Platform and how to get the raw data file from it. Today, I would like to show you a similar use case. We are going to export a selected report into a PDF file using our so called grey pages. Let&amp;#8217;s follow this workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find the Report Definition&lt;/li&gt;

&lt;li&gt;Compute the Report using the xTab Report executor and Report URI&lt;/li&gt;

&lt;li&gt;Get the new Report Result&lt;/li&gt;

&lt;li&gt;Export the created Report Result&lt;/li&gt;

&lt;li&gt;Download the Exported file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that you can use this workflow to integrate this feature to your custom App. The sample API calls are shown in our API Documentation.&lt;/p&gt;

&lt;p&gt;Well, what is the case&amp;#8230;I really like one of my report and I would like to export it and send it via email as an attachment. See the example below.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/reportGD.png' alt='GoodData Report' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;I would like to show you how you can use this flow to get the report in PDF/CSV/PNG. First of all, you’ll need to identify your selected report. Then find it (using grey pages) and get the Report Definition URI. Let&amp;#8217;s open up your browser and type in following address:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/PROJECT_ID/query/reports/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/Query-Report.png' alt='List of all Reports' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;In the url above, you can find a full list of your reports, choose the right one and you will get the Report description (in JSON format), where you can find the Report Result URI.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/Report-Res.png' alt='Report Resource' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The report description is what we need. In the picture above, you can see the green and red arrow. The green arrow is Report Result URI and the red arrow is Report URI. One Report could have a multiple Report Results. Latest Report Results is in the end of this part of JSON. What we need to tell the xTab report executor to compute the report is the Report URL. Let&amp;#8217;s copy it to a clipboard. We&amp;#8217;ll paste it into the corresponding input field on following resource:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/xtab2/executor3/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/Executor.png' alt='Report Executor' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;This is the Report executor. Here you can paste the previously copied Report URI and let the Executor to compute the latest Report Result. Again, you will get the Report Result JSON, but now with the updated results. This may take a while depending on report data size. During the report computation, API will return the 202 HTTP status. When computation is finished, copy the Report Result URI highlighted in the screenshot below.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/New-Report-Result.png' alt='New Report Result' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Now, with the latest Report Results URI in your clipboard, go to the Report Exporter that is located in following address&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/exporter/executor&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/export-to-pdf/Exporter.png' alt='Report Exporter' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;This resource represents the Report Exporter. It&amp;#8217;s the place where you can insert the Report Result URI and choose your preferred format. The Exporter will do its job and will give you the result URI, and also it is the place where you can download your exported report. Again, the report exporting will take a while. During the exporting process API will, as in previous step, give you the 202 HTTP status.&lt;/p&gt;

&lt;p&gt;Finally, the report in PDF is downloaded in your computer! Got it? Let&amp;#8217;s use it!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/N-YCV6wQock" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2012/01/06/Export-Report-To-PDF</feedburner:origLink></entry>
 
 <entry>
   <title>Advanced MAQL Reference Guide RELEASED!!!</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/W-6uj1bNCfs/MAQL-Reference-Guide" />
   <updated>2011-12-12T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/12/12/MAQL-Reference-Guide</id>
   <content type="html">&lt;h1 id='advanced_maql_reference_guide_released'&gt;Advanced MAQL Reference Guide RELEASED!!!&lt;/h1&gt;

&lt;p&gt;Folks,&lt;/p&gt;

&lt;p&gt;We have something special for you today. For the last few weeks, we’d been preparing the complete MAQL Reference Guide, that covers following topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MAQL Basics&lt;/li&gt;

&lt;li&gt;Operators&lt;/li&gt;

&lt;li&gt;Functions and macros&lt;/li&gt;

&lt;li&gt;Logical Expressions&lt;/li&gt;

&lt;li&gt;Common MAQL DDL Clauses&lt;/li&gt;

&lt;li&gt;Common MAQL DML Clauses&lt;/li&gt;

&lt;li&gt;MAQL Queries and subqueries (Metrics)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It covers the whole MAQL topic, and the complete guide has around 30 pages. As of today, you can download it and have it at your disposal while developing your Analytics App. The Reference Guide is well structured with tons of useful examples along with highlighted syntax.&lt;/p&gt;
&lt;center&gt;&lt;a href='/docs/reference-guide/Adv_MAQL_Ref_Guide.pdf' class='greenButton' onClick='_gaq.push([&amp;apos;_trackEvent&amp;apos;, &amp;apos;PDF&amp;apos;, &amp;apos;Download&amp;apos;, &amp;apos;MAQL Reference Guide&amp;apos;]);'&gt;Download the MAQL Reference Guide&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;Let us know what you think! And feel free to share it!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/W-6uj1bNCfs" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/12/12/MAQL-Reference-Guide</feedburner:origLink></entry>
 
 <entry>
   <title>Deleting Records from Datasets</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/1ikxM6TkI-k/Deleting-Records-Using-DML" />
   <updated>2011-12-12T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/12/12/Deleting-Records-Using-DML</id>
   <content type="html">&lt;h1 id='deleting_records_from_datasets'&gt;Deleting Records from Datasets&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Michael Stencl &amp;amp; Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not sure how to delete some data from your project? Well,we’ve already had an &lt;a href='http://developer.gooddata.com/blog/2011/05/03/deleting-data-from-project/'&gt;introduction&lt;/a&gt; to this particular topic, but by popular demand, we’ve been asked for some more examples. So, today we’ll show you some more tips and how-tos! The MAQL DML (Data Manipulation Language) is here for you! Also known by it’s powerful nickname - Destructive MAQL.&lt;/p&gt;

&lt;p&gt;It should be used very carefully, because if you delete the attribute value, You won’t be able to roll-back it. We have several use-cases which explain how powerful the delete command is. The most important issue is the referential integrity corruption.&lt;/p&gt;

&lt;p&gt;When deleting rows from an attribute table. You must keep in mind which of the affected values are directly connected to the fact through the facts of table (in our HR example LDM is the facts of table Salary). See the most general syntax of the delete statement below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attribute.factsof} WHERE &amp;lt;condition&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, you basically know what you can do by using it and it&amp;#8217;s to time to show you where to start. You want to start using it, right? GoodData doesn’t support running the DML statements from the UI, so you’ll need to navigate around the grey pages. The command line for running the DML statements is located in the following URL&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project_id&amp;gt;/dml/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can alsi use our gray pages to use DML. See the screenshot below:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/DML-Manage.png' alt='DML Gray Pages' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;We also extremely recommend you to validate your model before and after each DML statement to be sure no referential integrity errors are produced after your deletion.&lt;/p&gt;

&lt;p&gt;The following example deletes or destroys all of the rows in the Salary table:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a very unusual example because normally, we don’t like to delete all of the rows.&lt;/p&gt;

&lt;p&gt;We start with the condition construct. The conditions support most of the rational (&amp;gt;, &amp;lt;, =) and logical (AND, OR, NOT) operators. The left side of the condition can be defined from the fact element or the label defined on the attribute. The right hand side provides a value expression.&lt;/p&gt;

&lt;p&gt;The following example shows one of the elementary situations where we delete all the rows from Salary facts of table, where the value of payment is lower or equal to 10000. For now, the lower or equal sign (&amp;#8220;=&amp;lt;&amp;#8221;) is not supported in the DML conditioning.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary} WHERE {fact.salary.payment} &amp;lt; &amp;quot;10000&amp;quot; OR {fact.salary.payment}=&amp;quot;10000&amp;quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Another situation where the delete statement is very handy is when you need to delete all rows where the fact has zero value. This example is shown below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary} WHERE {fact.salary.payment}=0;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Think about a situation when you have some rows in fact tables where there are values of zero. In this situation, the facts Volume or Close price having zero value are affecting the resulting report. Then, we’ll need to delete all of the rows which have zero Volume or the Close Price is zero.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary} WHERE {fact.salary.payment}= 0 OR {label.salary.dt_payday} = &amp;quot;2010-02-29&amp;quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Still in need of some more examples? OK, we have something for you. Another example on how to delete rows from an attribute is by using the defined attribute label. If we want to delete all rows where the name of the person (defined by label) is Ed or Lin, we use following statement.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.employee.employee} WHERE {label.employee.employee.firstname} IN (&amp;quot;Ed&amp;quot;,&amp;quot;Lin&amp;quot;);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Another interesting use-case is deleting of the old data attribute values. For example when you need to delete all rows where the date is older than 1st January of 1999. See the example below&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary} WHERE {label.salary.dt_payday} &amp;lt; &amp;quot;2006-02-01&amp;quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The right handed side of the condtion (&amp;#8220;2006-02-01&amp;#8221;) must have the same format as defined by the label otherwise an error will be reported.&lt;/p&gt;

&lt;p&gt;Note that if you, by mistake, try to use anything other than a label in the condition of our delete statement, then an error occured. Note that you are not allowed to delete any rows from the date dimension provided by GoodData.&lt;/p&gt;

&lt;p&gt;Delete all rows where for the 2010 (all the dates are between 1st Jan and 31st Dec 2010). Again, we have an example. See below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE FROM {attr.salary.salary} WHERE {label.salary.dt_payday} BETWEEN &amp;quot;2010-01-01&amp;quot; AND &amp;quot;2010-12-31&amp;quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to delete any attribute value, you have to start by deleting the referencing attribute values of the attribute we’d like to delete. If you won&amp;#8217;t keep this workflow, referential integrity will be broken.&lt;/p&gt;

&lt;p&gt;So, if you want to delete department with ID = 1, you first have to delete all the employees who work in that department.&lt;/p&gt;

&lt;p&gt;Remember, after you finish all the delete operations, it’s important to validate your model again. The validation shows you the actual status and checks the referential integrity of the whole model.&lt;/p&gt;

&lt;p&gt;The validation is located in the grey pages of your projects which you can find in the following URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project_id&amp;gt;/validate/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let us know how it works! And for more information about MAQL, download our new Advanced MAQL Reference Guide&lt;/p&gt;
&lt;center&gt;&lt;a href='/docs/reference-guide/Adv_MAQL_Ref_Guide.pdf' class='greenButton' onClick='_gaq.push([&amp;apos;_trackEvent&amp;apos;, &amp;apos;PDF&amp;apos;, &amp;apos;Download&amp;apos;, &amp;apos;MAQL Reference Guide&amp;apos;]);'&gt;Download the MAQL Reference Guide&lt;/a&gt;&lt;/center&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/1ikxM6TkI-k" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/12/12/Deleting-Records-Using-DML</feedburner:origLink></entry>
 
 <entry>
   <title>Keboola Academy - hacking GoodData vol 01</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/pHPVtjoc6xA/Hacking-Gooddata-vol-1" />
   <updated>2011-12-09T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/12/09/Hacking-Gooddata-vol-1</id>
   <content type="html">&lt;h1 id='keboola_academy__hacking_gooddata_vol_01'&gt;Keboola Academy - hacking GoodData vol 01&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by &lt;a href='http://www.keboola.com'&gt;Keboola&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi, welcome to Keboola Academy!&lt;/p&gt;

&lt;p&gt;We love playing around with the GoodData platform. Recently for our friends at OpenBrand.com, we implemented an &amp;#8220;artificial intelligence&amp;#8221; solution powered by the GoodData engine. OpenBrand needed to analyze their user behavior in their Brand Management application, apply some logic to it and use results as input data for their recommendation engine. The logic is quite complicated, so we let GoodData take care of that :-)&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/KB_appschema.jpeg' alt='App Schema' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;So, please allow us to share with you how we managed to integrate an application with the extraneous GoodData BI platform.&lt;br /&gt;It&amp;#8217;s a bit tricky, but just follow the steps in this article, and you can accomplish the same thing quite easily.&lt;/p&gt;

&lt;p&gt;Firstly, for the purposes of this article, we need to assume that you already have a GoodData project loaded with data, and that you know the IDs (URIs) of the GoodData reports that you want to use. Also note that you must be authenticated prior to each API call as described &lt;a href='http://developer.gooddata.com/api/auth.html'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, to get the report results from GoodData to our external application is a two step process.&lt;/p&gt;

&lt;p&gt;First, we need to create a fresh report execution by using the GoodData &amp;#8220;Cross-Tabulation&amp;#8221; API. To do this, simply send a POST request to&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/xtab2/executor3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and add your report URI as a parameter.&lt;/p&gt;

&lt;p&gt;GoodData should respond with a &amp;#8220;200 Created&amp;#8221; code and return a URI object. Here is a sample request and response pair:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST https://secure.gooddata.com/gdc/xtab2/executor3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Accept: application/json&lt;/code&gt;&lt;br /&gt;&lt;code&gt;Content-Type: multipart/form-data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reportURI=&amp;quot;/gdc/md/{PID}/obj/{report_ID}&amp;quot;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example result:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
     &lt;span class='s2'&gt;&amp;quot;reportResult2&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
         &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
     
          &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
         &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
               &lt;span class='s2'&gt;&amp;quot;uri&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/gdc/md/{PID}/obj/{report_result_ID}&amp;quot;&lt;/span&gt;
         &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;
                   &lt;span class='p'&gt;}&lt;/span&gt;
     &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now that we have the up to date report results URI, we can send another POST method to the GoodData &amp;#8220;Export&amp;#8221; API (https://secure.gooddata.com/gdc/exporter/executor) to retrieve the raw data.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Request:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST https://secure.gooddata.com/gdc/exporter/executor&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Accept: application/json&lt;/code&gt;&lt;br /&gt;&lt;code&gt;Content-Type: multipart/form-data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uri=&amp;quot;/gdc/md/{PID}/obj/{report_result_ID}&amp;quot;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;format=&amp;quot;csv&amp;quot;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Response:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;   
     &lt;span class='s2'&gt;&amp;quot;uri&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/gdc/exporter/result/{PID}/{ID_of_raw_data}&amp;quot;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The response contains the URI that holds our raw data, and we can retrieve it with a GET request. Note that if the response status is &amp;#8220;202 Accepted&amp;#8221;, the data is not yet available. In this case, wait a few seconds and try again.&lt;br /&gt;When the data is ready, we receive a response with status &amp;#8220;200 OK&amp;#8221; and the response body contain the raw data we want.&lt;/p&gt;

&lt;p&gt;Request:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /gdc/exporter/result/{PID}/{ID_of_raw_data}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Good Luck!&lt;br /&gt;@Keboola&lt;br /&gt;&lt;p&gt;
&lt;img class='noborder' src='/images/posts/KB_keboolaAcademy.png' alt='Keboola Academy' /&gt;
&lt;/p&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/pHPVtjoc6xA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/12/09/Hacking-Gooddata-vol-1</feedburner:origLink></entry>
 
 <entry>
   <title>Let's get started with Mandatory User Filters</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/tDAfYyacFxQ/Mandatory-User-Filters" />
   <updated>2011-12-07T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/12/07/Mandatory-User-Filters</id>
   <content type="html">&lt;h1 id='lets_get_started_with_mandatory_user_filters'&gt;Let&amp;#8217;s get started with Mandatory User Filters&lt;/h1&gt;

&lt;p&gt;Hey, GoodData release #64 will be live pretty soon and you’ll definitely be interested in what we have in store for you. Mandatory User Filters&amp;#8230;Not sure what to expect? Let&amp;#8217;s imagine the following situation: Your company has multiple departments, for example: Engineering, Accounting, HR etc.&lt;/p&gt;

&lt;p&gt;Let’s say, you&amp;#8217;d like to create a report, but want to set a filter for a specific user. Imagine, we would like to allow one user to see only numbers for a specific department (i.e. Human Resources), because there is no need to let him check the other department&amp;#8217;s numbers. How can we do that?&lt;/p&gt;

&lt;p&gt;Go through the following example and after reading it, the new user filter will be created. In practice, we will filter the report by a specific attribute element (attribute value).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Attribute = Department&lt;/code&gt;&lt;br /&gt;&lt;code&gt;Attribute element = Human Resources&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;First of all, lets check the report without the Mandatory User Filter defined. The user will see the following:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/Report-without-muf.png' alt='Report Without MUF' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; This time you can filter by attribute elements. It is not possible to filter report i.e. by metric.&lt;/p&gt;

&lt;h2 id='the_basics'&gt;The Basics&lt;/h2&gt;

&lt;p&gt;As always, we prepare a simple API, so you can play around and start integrating into your Apps!&lt;/p&gt;

&lt;p&gt;So, let&amp;#8217;s start. The Mandatory User Filter is a standard object in our platform. As any other object, it has a URI and you can set it up using API or find it using the gray pages at &lt;code&gt;md/query/&lt;/code&gt; context. The steps will be the following:&lt;/p&gt;

&lt;p&gt;1) Create a new user filter object&lt;br /&gt;2) Assign the user filter object to the user/users&lt;br /&gt;3) Check the functionality&lt;/p&gt;

&lt;h2 id='creating_new_mandatory_filter_object'&gt;Creating new Mandatory Filter Object&lt;/h2&gt;

&lt;p&gt;To create a new Mandatory Filter Object, you must be logged as an Admin. Creating a new Mandatory Filter Object is very similar to our other API calls. You need to define json, and POST it to the specific resource. See the screenshot from our popular REST Client for Firefox.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/REST-Client-payload.png' alt='REST Client Payload' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The resource for creating new Mandatory User Filters is the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/obj&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is the specific json payload:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;userFilter&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;expression&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;[/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;object-id&amp;gt;]=[/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;object-id&amp;gt;/elements?id=&amp;lt;element-id&amp;gt;]&amp;quot;&lt;/span&gt;
        &lt;span class='p'&gt;},&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;category&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;userFilter&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;User filter - HR Department&amp;quot;&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;They key part is in the expression statement, where you define an expression for the given user filter. You can not only use &lt;code&gt;=&lt;/code&gt;, but also &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;, &lt;code&gt;IN&lt;/code&gt; or &lt;code&gt;NOT IN&lt;/code&gt; inside an expression.&lt;/p&gt;

&lt;p&gt;The only “tricky part” is that you need to know an attribute ID and attribute element ID. The easiest way how to get these identifiers is to use our “so called” gray pages. Go to following page:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/query/attributes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, select your attribute and find the URI down in meta section. Then, you&amp;#8217;ll need to specify the attribute element that corresponds to the Human Resources Department. This can be done by using the elements link that will give you a list of all attribute elements. You can find it and use it&amp;#8217;s identifier in the json payload that is shown above.&lt;/p&gt;

&lt;p&gt;The API response is 200 HTTP header and URI of newly created User Filter Object. As a next step, check the user filter existence by calling GET to the following resource:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;created-object-id&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2 id='assign_the_muf_to_the_user_object'&gt;Assign the MUF to the User object&lt;/h2&gt;

&lt;p&gt;Once we have the new filter defined, it&amp;#8217;s time to assign it to a user. Similar to the previous step, you&amp;#8217;ll need to specify user ID, you can find it on &lt;code&gt;/gdc/projects/&amp;lt;project-id&amp;gt;/users&lt;/code&gt;, where you can find all users in the project and select the corresponding identifier.&lt;/p&gt;

&lt;p&gt;The following resource and payload will connect the user with the user filter.&lt;/p&gt;

&lt;p&gt;Note: You can, for sure, specify multiple filters for one user.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/userfilters&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt; 
	&lt;span class='s2'&gt;&amp;quot;userFilters&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;items&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='s2'&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/gdc/account/profile/&amp;lt;user-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                &lt;span class='s2'&gt;&amp;quot;userFilters&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
                    &lt;span class='s2'&gt;&amp;quot;/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;user-filter-object-id&amp;gt;&amp;quot;&lt;/span&gt;
                &lt;span class='o'&gt;]&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;As a response, you&amp;#8217;ll get json with the information that tells you whether the user filter was assigned to the user. Have a look at this example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;userFiltersUpdateResult&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;failed&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='o'&gt;[]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;successful&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
           &lt;span class='s2'&gt;&amp;quot;/gdc/account/profile/&amp;lt;profile-id&amp;gt;&amp;quot;&lt;/span&gt;
        &lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Everything went smooth, right? So let&amp;#8217;s check the report numbers visibility for a defined user. See the report:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/Filtered-Report.png' alt='Filtered Report' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Well, that&amp;#8217;s all for today. Let us know your opinion, ideas and feedback. We can&amp;#8217;t wait to hear (and also see) how you, developers, are using the features that we are bringing to you. We are driven by your passion in using our tools and API&amp;#8217;s. Stay tuned for next time!!!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/tDAfYyacFxQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/12/07/Mandatory-User-Filters</feedburner:origLink></entry>
 
 <entry>
   <title>Time over Time Comparison</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/RdwL3bKNnBE/time-over-time-comparison-reports" />
   <updated>2011-11-25T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/11/25/time-over-time-comparison-reports</id>
   <content type="html">&lt;h1 id='time_over_time_comparison'&gt;Time over Time Comparison&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi everybody! No matter if you work on a killer Analytics App, or just started using GoodData, you’ll always want to learn something new. I hope I’ve got something for you. Today I would like to teach you how to use transformations in metrics.&lt;/p&gt;

&lt;p&gt;First, let me introduce the problem. Imagine you are a data analyst and you would like to create a time over time comparison report for your Sales Director to have a better overview of the company&amp;#8217;s sales data from your SalesForce CRM. Got it? Let&amp;#8217;s do it!&lt;/p&gt;

&lt;h2 id='time_over_time_comparison_reports'&gt;Time over Time Comparison reports&lt;/h2&gt;

&lt;p&gt;What will you need? You&amp;#8217;ll definitely need some good data, and some knowledge on how to create these type of metrics with MAQL (our query language). Starting with one of the simplest metrics in Sales Analytics - &lt;code&gt;Amount[SUM]&lt;/code&gt;. This metric is predefined by default in our Sales Analytics App and gives you a total amount of all opportunities for the last snapshot. Remember that in Sales Analytics, you need to specify the snapshot. Not sure what snapshots are about? &lt;a href='http://developer.gooddata.com/blog/2011/07/29/Analyzing-Change/'&gt;Read this article&lt;/a&gt; first to be sure how to use it!&lt;/p&gt;

&lt;p&gt;Now, let&amp;#8217;s tune it up to see a time over time comparison! See the metrics below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT Amount[SUM] FOR Previous(Quarter/Year(Closed))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT Amount[SUM] FOR PreviousPeriod(Quarter/Year(Closed))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first metric computes a number for a previous specific period of time. If you use this metric side by side with the basic &lt;code&gt;Amount[SUM]&lt;/code&gt; and slice them by Quarter/Year and Month/Year. The metric is used in the report shown below.&lt;/p&gt;

&lt;p&gt;The second metric is different from the first one. The &lt;code&gt;FOR PreviousPeriod()&lt;/code&gt; is used there. What is the difference between the FOR Previous and FOR PreviousPeriod statement? The FOR Previous is connected to the date dimension and gives you the aggregation based on previous time period from the date dimension. In our example, it gives you the same month but from the previous quarter. The FOR PreviousPeriod gives you a previous value based on records in report. See the examples in a report and tables below.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/ForPreviousQuarter-report.png' alt='For Previous Quarter Report' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Got it? Do you see the difference? The report above and metrics with Previous statements are based on Quarter level. In the tables below, you can see more examples to understand it clearly:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/PreviousMonth.png' alt='For Previous Month' /&gt;&lt;/center&gt;
&lt;/p&gt;&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/PreviousQuarter.png' alt='For Previous Quarter' /&gt;&lt;/center&gt;
&lt;/p&gt;&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/PreviousYear.png' alt='For Previous Year' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Anyway, what you can also use is a second parameter inside both statements. It&amp;#8217;s a number that tells the engine to skip the given number of the period. Again, for better understanding, see the example below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT Amount[SUM] FOR PreviousPeriod(Quarter/Year(Closed),2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see, with additional parameter added to the metric specification, it skips two Quarters and gives you the corresponding number.&lt;/p&gt;

&lt;p&gt;Alternatively, it is also possible to compare against future dates using two other special MAQL functions: FOR Next() and FOR NextPeriod(). Both of these constructs function in the same was as FOR Previous() and FOR PreviousPeriod() above.&lt;/p&gt;

&lt;h2 id='year_to_date_reports'&gt;Year to Date Reports&lt;/h2&gt;

&lt;p&gt;Another use that I would like to show you is Year to Date Reports and metrics. Using this special construct, you can create a metric with “This” as a day or “Yesterday”. For better understanding, let&amp;#8217;s see a simple example&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT Amount [SUM] WHERE Quarter/Year(Closed) = {This}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The metric above gives you Amount of all opportunities that were closed this Quarter. You can also use &lt;code&gt;{This} - 1&lt;/code&gt; that is the same as &lt;code&gt;{Previous}&lt;/code&gt; statement. Not enough? Let&amp;#8217;s combine it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT Amount [SUM] WHERE Quarter/Year(Closed) = {Previous} AND Day of Quarter = {This}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example, &lt;code&gt;{Previous}&lt;/code&gt; would mean &amp;#8220;Previous (Last) Quarter&amp;#8221; and &lt;code&gt;{This}&lt;/code&gt; would refer to &amp;#8220;Today as a numeric Day of the Quarter&amp;#8221; (i.e., Day 62 of the quarter).&lt;/p&gt;

&lt;p&gt;So, let your imagination work! Use transformation, be creative and&amp;#8230;data driven ;) See you next time!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/RdwL3bKNnBE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/11/25/time-over-time-comparison-reports</feedburner:origLink></entry>
 
 <entry>
   <title>New CL Tool v.1.2.43 released</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/dVfyqm2_V4s/CL-Tool-1-2-43-Release" />
   <updated>2011-11-21T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/11/21/CL-Tool-1-2-43-Release</id>
   <content type="html">&lt;h1 id='new_cl_tool_v1243_released'&gt;New CL Tool v.1.2.43 released&lt;/h1&gt;

&lt;p&gt;We would like to tell you that we released a new CL tool version &lt;code&gt;1.2.43&lt;/code&gt;. This version contains following fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many internal fixes improvements and code polishing from the GoodData engineering code review.&lt;/li&gt;

&lt;li&gt;Improved gdi.bat script that correctly reports error to the calling script.&lt;/li&gt;

&lt;li&gt;Improved compatibility with the Java 7.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can &lt;a href='https://github.com/gooddata/GoodData-CL/downloads'&gt;download it from Github now&lt;/a&gt;! If you have any questions, feel free to ask us!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/dVfyqm2_V4s" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/11/21/CL-Tool-1-2-43-Release</feedburner:origLink></entry>
 
 <entry>
   <title>Add user to project with REST API</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/i2U_iIY1Pzk/Adding-User-To-Project-Using-API" />
   <updated>2011-11-07T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/11/07/Adding-User-To-Project-Using-API</id>
   <content type="html">&lt;h1 id='add_user_to_project_with_rest_api'&gt;Add user to project with REST API&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dear Developers,&lt;/p&gt;

&lt;p&gt;We are quite often asked about how to add users to a project using GoodData REST API. We already have description on how to use the &lt;a href='http://developer.gooddata.com/blog/2011/07/14/add-user-to-project/'&gt;CL Tool to add users programmatically&lt;/a&gt;. We are very aware of the fact that some of you are not really well versed using our CL Tool and would prefer the REST API way. If the REST API&amp;#8217;s are your cup of tea, this blogpost is for you.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s go through a simple example on how to use our User Provisioning API. First, you’ll need to create the project where you want to add the user. Basically, we will go through following three steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a project&lt;/li&gt;

&lt;li&gt;add user to a domain&lt;/li&gt;

&lt;li&gt;add user to a project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just one more thing before we really start applying our API calls. You’ll need to set the Content-type header parameter to application/json and most of time you will send a json in the REST API calls.&lt;/p&gt;

&lt;h2 id='project_creation'&gt;Project Creation&lt;/h2&gt;

&lt;p&gt;No project - No place to add users. As mentioned before, this should be the first step because if there is no project, then we won’t have a place to add the users.&lt;/p&gt;

&lt;p&gt;Firstly, you can call the API to get a list of your projects. This can be a bit tricky because the resource for getting all of your projects is not located on &lt;code&gt;/gdc/projects&lt;/code&gt; but on &lt;code&gt;gdc/md&lt;/code&gt;. That means by calling GET to&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything is OK, you’ll get HTTP 200 parameter as a response.&lt;/p&gt;

&lt;p&gt;Now, let&amp;#8217;s create a new project. Send POST http request to following resource&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/projects&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;project&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; 
     &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; 
         &lt;span class='s2'&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;New Project&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; 
         &lt;span class='s2'&gt;&amp;quot;summary&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;A new project&amp;quot;&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt; 
     &lt;span class='s2'&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;state&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;ENABLED&amp;quot;&lt;/span&gt; 
&lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You should get a 201 Created header as a response with created project information in a body:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;uri&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;/gdc/projects/&amp;lt;project-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='user_creation'&gt;User Creation&lt;/h2&gt;

&lt;p&gt;We’ve got the project created, so now, we have a destination for the users we want to add. What we need to do now is to create a new user. There are several things to keep in mind here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to have a domain set up&lt;/li&gt;

&lt;li&gt;Only owner of the domain can use POST AccountSetting on this resource&lt;/li&gt;

&lt;li&gt;Password and verifyPassword must match, otherwise the resource reports validation error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does this mean? It means if you don&amp;#8217;t have a domain created, you’ll need to ask our operations team to create it for you. You can ask them via our Support Portal.&lt;/p&gt;

&lt;p&gt;The domain has already been created. You are authenticated. So now, It&amp;#8217;s time to provision users to your domain. Again, this is done via the REST API call. Use POST request to the&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/add-user-to-domain.png' alt='Add user to domain' /&gt;&lt;/center&gt;
&lt;/p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
 &lt;span class='s2'&gt;&amp;quot;accountSetting&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;login&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user@login.com&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;PASSWORD&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;verifyPassword&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot; PASSWORD &amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;firstName&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;FirstName&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;lastName&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;LastName&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
 &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This should be a response if everything was POSTed accurately:&lt;/p&gt;

&lt;p&gt;(201 Created) % an uri of newly created user in format &lt;code&gt;/account/profile/&amp;lt;user-id&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/user-created.png' alt='Add user to project' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Nice! We&amp;#8217;ve just created new user in our domain!&lt;/p&gt;

&lt;h2 id='add_user_to_a_project'&gt;Add user to a project&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s continue with our story, this is not the end. Remember what we want to do? Sure, we would like to add user to a specific project. How do we do it? Use POST &lt;code&gt;.json&lt;/code&gt; to following resource:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/add-user-to-project.png' alt='Add user to project' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Following example will add new user that is identified by userId to the project in specific role (role and project are also specified by ID). Role ids are the following:&lt;/p&gt;

&lt;p&gt;(1: Admin; 2: Editor; 3: Embedded dashboard only)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
     &lt;span class='s2'&gt;&amp;quot;content&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
           &lt;span class='s2'&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;ENABLED&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
           &lt;span class='s2'&gt;&amp;quot;userRoles&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;/gdc/projects/&amp;lt;project-id&amp;gt;/roles/&amp;lt;role-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
                 &lt;span class='p'&gt;},&lt;/span&gt;
     &lt;span class='s2'&gt;&amp;quot;links&amp;quot;&lt;/span&gt;   &lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
           &lt;span class='s2'&gt;&amp;quot;self&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;/gdc/account/profile/&amp;lt;user-id&amp;gt;&amp;quot;&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If the API gives you a Header 200 respond, that’s a reason to smile because you have successfully added the user! Now, you are ready to integrate these calls to your custom apps.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/user-provisioned.png' alt='Add user to domain' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;One more thing. If you use &lt;code&gt;status: DISABLED&lt;/code&gt; in user provisioning &lt;code&gt;json&lt;/code&gt; file (shown above), you are able to disable the user from the project.&lt;/p&gt;

&lt;p&gt;Let me know what you think! Best Regards,&lt;/p&gt;

&lt;p&gt;JT&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/i2U_iIY1Pzk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/11/07/Adding-User-To-Project-Using-API</feedburner:origLink></entry>
 
 <entry>
   <title>The Event Store Introduction</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/o2TC5EPMzkE/The-Event-Store-Introduction" />
   <updated>2011-10-26T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/10/26/The-Event-Store-Introduction</id>
   <content type="html">&lt;h1 id='the_event_store_introduction'&gt;The Event Store Introduction&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello all you analysis ninjas! Today I&amp;#8217;d like to start a huge topic which is very wide and will cover multiple blogposts. I would like to introduce you to a brand new data warehousing technology that we developed in the GoodData Platform. We have been using it internally some time and now, it’s time to release it to the public, so anyone of you GD developers, can start building analytics projects and apps using this new technology.&lt;/p&gt;

&lt;h2 id='snapshotting'&gt;Snapshotting&lt;/h2&gt;

&lt;p&gt;Remember earlier &lt;a href='http://developer.gooddata.com/blog/2011/07/29/Analyzing-Change/'&gt;Analyzing Changes&lt;/a&gt; blogpost? I hope so! If you want to use the snapshotting technique you need to store all your data somewhere. By storing your complete data, you&amp;#8217;ll have access to all of the data snapshots in your storage and you will be able to analyze changes.&lt;/p&gt;

&lt;p&gt;Imagine that you have, let’s say, about 100k rows of data in your SalesForce application and you would like to upload it on regular basis (i.e. weekly). You also want to store all weekly loads, because you&amp;#8217;ll need to have the history of data values. This is very memory consuming process.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/event-store/snapshots.png' alt='Reports' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;See the picture above. Only one row was changed, but we loaded all three rows. Until now, you&amp;#8217;ve had to upload all of the data repeatedly which can be inefficient. In the classic data warehouse system, every record is loaded every time you upload your data. Every time you start loading data from the source system to your data warehouse, it will be a full load no matter if the data was changed or not. The size of your data warehouse increases very quickly.&lt;/p&gt;

&lt;p&gt;We need something different. We need to use a better approach with more sophisticated technology. We need the Event Store!&lt;/p&gt;

&lt;h2 id='the_new_era'&gt;The New Era&lt;/h2&gt;

&lt;p&gt;At GoodData, we&amp;#8217;ve worked very hard to develop a better data warehouse. Something that will help you work with a huge amount of data easily and dynamically. We needed something that won’t be wasting the data warehouse memory and also help you with the whole ETL process.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/event-store/es_schema.png' alt='Data Integration' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;What we&amp;#8217;ve created here is brand new data warehousing technology. It&amp;#8217;s called the EventStore. The EventStore decreases of the amount of data in your data warehouse but keeps all your historical data.&lt;/p&gt;

&lt;p&gt;Imagine, you are using Salesforce as your CRM solution and you want to analyze your data to get some regular insights. You need to have your data up-to-date in your BI system. Also, you want to keep your historical data in order to look back in retrospect and as we have mentioned earlier, the classic approach fails here. How does the Event Store work?&lt;/p&gt;

&lt;p&gt;The EventStore creates a special stream for every field. Every time you start loading your data that you had been previously downloaded from the source system (i.e. Salesforce, SugarCRM) the Event Store checks the corresponding stream. If there are some changes since the last upload, the Event Store will update them with a new record value. It also stores historic values.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/event-store/record_stream.png' alt='Record Stream' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As you can see, the size of your data warehouse will be increasing much slower, than if you use the classic storage.&lt;/p&gt;

&lt;p&gt;The EventStore will enable you to load the data for a specific time period and with a specific granularity. You will be able to load for example all daily snapshots between beginning of the Quarter and Today. You can create another project and load a monthly snapshots from the EventStore here. As a result today, you will get a CSV file that you can upload to the GoodData Platform, create metrics, prepare reports and dashboards.&lt;/p&gt;

&lt;h2 id='more_features_to_come'&gt;More Features to Come&lt;/h2&gt;

&lt;p&gt;Keeping your data warehouse at a reasonable size while, at the same time, keeping your data history isn&amp;#8217;t the only feature. These are just basics. With Event Store, you will be able to make a transformation on an output and prepare pre-aggregated data or compute values. More features and integrations are coming up in a near future.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next blogpost of the Event Store series, where I will show you examples on how to start using Event Store in your projects. This is just a beginning.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/o2TC5EPMzkE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/10/26/The-Event-Store-Introduction</feedburner:origLink></entry>
 
 <entry>
   <title>How to use COUNT in metrics</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/X-7Wk0Nivh4/using-count-metrics" />
   <updated>2011-10-17T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/10/17/using-count-metrics</id>
   <content type="html">&lt;h1 id='how_to_use_count_in_metrics'&gt;How to use COUNT in metrics&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;New to GoodData? Do you want to start creating some effective dashboards with your reports, then you&amp;#8217;ll need to know how to create metrics. As mentioned earlier, in most cases, metrics are aggregated facts. However, sometimes you need to count non fact elements which are called attributes. Check out the following model, here I&amp;#8217;ll explain how to create a &lt;code&gt;COUNT&lt;/code&gt; metric.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/count_model.png' alt='Count Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The COUNT metric can be used with one or two arguments. Let’s see how it works in some common use cases.&lt;/p&gt;

&lt;h2 id='counting_a_number_of_salaries'&gt;Counting a number of salaries&lt;/h2&gt;

&lt;p&gt;Based on our model, Imagine that you are faced with the following scenario: you would like to create a simple metric that counts the number of salaries that had been paid. In this example, you&amp;#8217;ll count the distinct values of an attribute (non-countable field). Therefore, you&amp;#8217;ll need to use &lt;code&gt;SELECT COUNT(Salary ID)&lt;/code&gt; as the metric definition in order to get the results you are looking for. This metric itself is not so useful but we can show the COUNT concept using it.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/number_of_salary_metric.png' alt='Count Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;If you look on our model, you see that the &lt;code&gt;Salary ID&lt;/code&gt; is not connected to other attributes and you are not able to slice and dice the metric that is defined as &lt;code&gt;COUNT(Salary ID)&lt;/code&gt;. Try to define a report with this metric now. You see that other attributes (Employee,&amp;#8230;) are greyed out (see the screenshot below). The &lt;code&gt;COUNT&lt;/code&gt; here focuses solely on the Attribute and always returns the same number.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/undrillable.png' alt='Undrillable' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h2 id='counting_employees_that_were_paid'&gt;Counting Employees that were paid&lt;/h2&gt;

&lt;p&gt;Now let’s say you want to do something a bit different. Let’s say that you want to &lt;code&gt;COUNT&lt;/code&gt; number of Employees that were paid a salary. Then you will need to explain what you want to count. If you put an Employee together with a Salary in a report to count the number of employees with salary, then this is the time when you would need to use the second &lt;code&gt;COUNT&lt;/code&gt; function parameter.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/employee_with_salary.png' alt='Count Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The Records of Salary attribute is needed to count the number of Employees that were paid a Salary. The metric syntax is &lt;code&gt;COUNT(Employee, Records of Salary)&lt;/code&gt; as shown above.&lt;/p&gt;

&lt;p&gt;You have two options how to create this type of metric. The first option is to add new metric from report dialog. Here, select the &lt;code&gt;COUNT&lt;/code&gt; operation, then choose any attribute and the count metric with two arguments is created. If the attribute that you want to compute is connected to more than one dataset, you have also specify, which dataset you want to compute.&lt;/p&gt;

&lt;p&gt;The second option is to use the Advanced Metric Editor to create this metric. Click the “advanced” link in the WHAT dialog menu, then follow the Custom metric link, make sure you name your metric (e.g. # Employees with Salary) and insert the metric definition:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT COUNT(Employee,Records of Salary)&lt;/code&gt;&lt;/p&gt;

&lt;h2 id='advanced_examples'&gt;Advanced examples&lt;/h2&gt;

&lt;p&gt;And the last but not least, we would like to show you some more advanced tips that you can use with the COUNT metric to improve your reporting. Keeping in mind our model, we would like to know how many employees from the store management were paid a salary greater than $5,000.&lt;/p&gt;

&lt;p&gt;You can create a COUNT metric with a filter to find it out.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT COUNT(Employee,Records of Salary) WHERE Department = Store Management AND Salary &amp;lt; 5000&lt;/code&gt;&lt;br /&gt;&lt;code&gt;SELECT COUNT(Employee,Records of Salary) WHERE Department = Human Resources AND Salary &amp;lt; 7500&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;etc&amp;#8230;&lt;/p&gt;

&lt;p&gt;Again, you&amp;#8217;ll need to use the Advanced Metric Editor to create these metrics.&lt;/p&gt;

&lt;p&gt;Happy counting!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/X-7Wk0Nivh4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/10/17/using-count-metrics</feedburner:origLink></entry>
 
 <entry>
   <title>MongoDB Behind the Scenes</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/HGSzTdLuNHU/Mongodb-behind-the-scene" />
   <updated>2011-10-06T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/10/06/Mongodb-behind-the-scene</id>
   <content type="html">&lt;h1 id='mongodb_behind_the_scenes'&gt;MongoDB Behind the Scenes&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Roman Pichlik&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some time ago, &lt;a href='http://twitter.com/jirtob'&gt;Jiri Tobolka&lt;/a&gt; wrote a nice &lt;a href='http://developer.gooddata.com/blog/2011/09/13/Notifications-API/'&gt;introduction&lt;/a&gt; to the Notifications API on the GoodData platform. I would like to share with you the technical details behind the scenes, especially some details about the storage engine we&amp;#8217;ve used for the notifications data&amp;#8230;&lt;/p&gt;

&lt;p&gt;There are three main entities in the Notification domain model - &lt;em&gt;ChannelConfiguration&lt;/em&gt;, &lt;em&gt;Subscription&lt;/em&gt; and &lt;em&gt;Trigger&lt;/em&gt;. Their relationships are on the next picture.&lt;/p&gt;
&lt;center&gt;&lt;img src='/images/posts/mongo-1.png' alt='Reports' /&gt;&lt;/center&gt;
&lt;p&gt;We had been facing the issue of how to persist these entities. In the GoodData platform we keep most of data in the good old relational database (RDBMS), but we are all aware of the constraints. One year ago, we did a proof of concept for storing the data out of the relational database because the characteristics of the data didn&amp;#8217;t fit into the relational model. Let me explain it in the Notifications model example.&lt;/p&gt;

&lt;p&gt;We mentioned that the Notifications consisted of three entities. If we had chosen a relational database for storing them, we would have probably ended up with a normalized schema as you can see in the next picture.&lt;/p&gt;
&lt;center&gt;&lt;img src='/images/posts/mongo-2.png' alt='Reports' /&gt;&lt;/center&gt;
&lt;p&gt;There are seven tables if we count the join tables required for many-to-many relationships. Such a normalized schema would cause a couple of problems. We would have to add a new table for every new channel. We would also have to use the left outer join for querying subscription with associated channels and use cascade deletion on a database level or in application logic because of referral integrity.&lt;/p&gt;

&lt;p&gt;We could store these entities as BLOBs but in this case, it wouldn&amp;#8217;t be the best option because we wouldn&amp;#8217;t be able to query such documents e.g. get me all notifications for project X.&lt;/p&gt;

&lt;h2 id='document_oriented_databases'&gt;Document Oriented Databases&lt;/h2&gt;

&lt;p&gt;The mental shift here is to realize that we deal with documents. We store, get, update, query and delete documents. We have been looking for a document oriented database. There are great NoSQL databases like Riak, Cassandra, Redis, HBase but most of them are key/value oriented. That means that if we were to use some of these NoSQL options would have to transform our documents to key/value structures with almost zero benefits over the conventional RDBMS.&lt;/p&gt;

&lt;p&gt;Even with a document oriented database some concepts are similar to RDBMS. Documents are organized in collections. Collections are something like database tables in RDBMS. A collection allows you to store documents with a different structure or even type which is opposite to a database table where the structure is determined by columns and their types. We can say that document fields correspond with table columns, but there are differences such as, no strict type or schema. In general, there are no schema requirements for your documents, fields or collections. We call these databases schema-less.&lt;/p&gt;

&lt;p&gt;It brings some advantages and disadvantages or things that should be kept in mind. When you want to add new fields in a new version of a document, you can migrate the old versions on the fly in runtime and reduce server downtime, for example. On the other hand, there are no data consistency constraints on the storage level and you can enforce them only in an application logic.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s go back and see how the Notifications documents can be stored in a document-oriented database. There are two collections for channels and subscriptions. Documents are self-contained. A subscription document contains trigger definitions and meta definitions, for example. The relationship between channels and subscriptions are expressed weakly. Only an ID of a related channel document is held. There is no foreign key constraint. Documents can be updated or deleted independently and consistency is checked in an application logic.&lt;/p&gt;
&lt;center&gt;&lt;img src='/images/posts/mongo-3.png' alt='Reports' /&gt;&lt;/center&gt;
&lt;p&gt;If we are talking about a document oriented database then there are two well known solutions &lt;em&gt;MongoDB&lt;/em&gt; and &lt;em&gt;CouchDB&lt;/em&gt;. The fundamental difference between &lt;em&gt;MongoDB&lt;/em&gt; and &lt;em&gt;CouchDB&lt;/em&gt; is in querying and accessing the data. The &lt;em&gt;CouchDB&lt;/em&gt; queries are expressed as Map/Reduce functions. Queries are special documents called views that contain defined Map/Reduce functions. You won&amp;#8217;t be able to query data unless you define a view. The &lt;em&gt;MongoDB&lt;/em&gt; queries are expressed as structured JSON-objects. &lt;em&gt;MongoDB&amp;#8217;s&lt;/em&gt; approach is more declarative opposite to &lt;em&gt;CouchDB&lt;/em&gt;. You can define indexes over stored documents and a get performance boost when querying over fields in these indexes. &lt;em&gt;MongoDB&lt;/em&gt; allows dynamic queries where an index does not exist. That&amp;#8217;s very similar to RDBMS world. In addition &lt;em&gt;MongoDB&lt;/em&gt; supports Map/Reduce as well, but it&amp;#8217;s intended for data processing, not querying.&lt;/p&gt;

&lt;p&gt;Documents in &lt;em&gt;CouchDB&lt;/em&gt; are accessed over HTTP and REST interface. &lt;em&gt;MongoDB&lt;/em&gt; uses a proprietary binary protocol on top of TCP/IP and therefore language specific driver is required.&lt;/p&gt;

&lt;h2 id='mongodb'&gt;MongoDB&lt;/h2&gt;

&lt;p&gt;After considering all requirements and technological constraints we chose &lt;em&gt;MongoDB&lt;/em&gt; over &lt;em&gt;CouchDB&lt;/em&gt;. The main reasons are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;querying capabilities - In general, querying data in &lt;em&gt;MongoDB&lt;/em&gt; is more of a natural way than thinking in Map/Reduce.&lt;/li&gt;

&lt;li&gt;driver - performance, very handy for clients&lt;/li&gt;

&lt;li&gt;scalability - &lt;em&gt;MongoDB&lt;/em&gt; supports (no hacks) sharding functionality by default. That&amp;#8217;s very important for a SAAS provider such as GoodData.&lt;/li&gt;

&lt;li&gt;tools - backup/restore/monitoring utilities, administration console, JSON and JavaScript as a first class citizen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;MongoDB&lt;/em&gt; was successfully deployed on the production servers and developer machines. We use &lt;em&gt;MongoDB&lt;/em&gt; with enabled journaling even if it has some performance penalties. This is not problem since we have mostly read operations. The second option would be deploy &lt;em&gt;MongoDB&lt;/em&gt; in a cluster with replicating nodes. &lt;em&gt;MongoDB&lt;/em&gt; supports auto-sharding, so we can shard data on a project base in the future.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/HGSzTdLuNHU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/10/06/Mongodb-behind-the-scene</feedburner:origLink></entry>
 
 <entry>
   <title>Migrating Selected Objects between Projects</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/21MUyyej2Wc/Migrating-Objects-between-Projects" />
   <updated>2011-09-26T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/09/26/Migrating-Objects-between-Projects</id>
   <content type="html">&lt;h1 id='migrating_selected_objects_between_projects'&gt;Migrating Selected Objects between Projects&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi there! Do you have multiple projects based on one project template or multiple projects cloned from one master project? Do you dream of a simple way how to copy new metrics or reports between projects?&lt;/p&gt;

&lt;p&gt;Selected object migration is a new feature that has been implemented in GoodData since our latest release which was Release 60. So this is the way how to start!&lt;/p&gt;

&lt;h2 id='project_cloning'&gt;Project Cloning&lt;/h2&gt;

&lt;p&gt;You probably know that it is possible to clone (export/import) the whole GoodData project. If not, find out more about &lt;a href='http://developer.gooddata.com/blog/2011/06/06/project-cloning/'&gt;how to clone project&lt;/a&gt; in our previous blogpost.&lt;/p&gt;

&lt;h2 id='exportimport_selected_objects'&gt;Export/Import Selected Objects&lt;/h2&gt;

&lt;p&gt;First of all, before we start migrating objects, keep in mind a few things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every object has its unique uri.&lt;/li&gt;

&lt;li&gt;Projects must have the same logical data model if you want to migrate objects between them.&lt;/li&gt;

&lt;li&gt;Migration works with metrics, reports and dashboards.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Imagine that you have a project template and several child projects (projects based on that template) that you want to populate with new reports or metrics or dashboards. Sounds simple enough, doesn’t it? Let’s see how you can do it!&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a simple example. We created two HR projects (based on our well known &lt;a href='http://developer.gooddata.com/gooddata-cl/examples/hr/'&gt;CL Tool example&lt;/a&gt;, with the same LDM). Let’s say the first one is a sandbox project where we want to play around with metrics, prepare reports etc. The second one is customer’s project where we want to copy only objects (reports, metrics, etc.) that are prepared for the customer.&lt;/p&gt;

&lt;p&gt;What we are going to do is to prepare a nice report in our “master” project and then we will copy this report to the child HR Demo Copy project. Follow this example and you&amp;#8217;ll know how to do it via the so called grey pages and also with the CL Tool!&lt;/p&gt;

&lt;p&gt;We will skip the report creation part (you can read more about creating reports &lt;a href='http://developer.gooddata.com/blog/2011/08/17/how-to-create-project-in-gooddata/'&gt;here&lt;/a&gt;) and will continue on with exporting. As you can see below, we’ve created two reports in the HR project (which is our sandbox) and we&amp;#8217;ve decided that the Total Payment by Quarter report is ready and we want to copy it to the HR Demo Copy project.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/2.png' alt='Reports' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As you can see below, the HR Demo Copy is empty.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/4.png' alt='New project' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You have to be logged in as one user when you do export/import. It is not possible to export metadata, send token to other user to import metadata.&lt;/p&gt;

&lt;h2 id='exporting_objects'&gt;Exporting objects&lt;/h2&gt;

&lt;p&gt;Our report is prepared and now we need to export it from the HR project.&lt;/p&gt;

&lt;p&gt;We have several options how to export reports (or dashboards, metrics) from the project. The first option is to use the newly implemented CL Tool commands. The second option is to use our grey pages. Firstly, let’s see how to do it with CL Tool:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UseProject(fileName=&amp;quot;...&amp;quot;);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;ExportMetadataObjects(tokenFile=&amp;quot;...&amp;quot;, objectIDs=&amp;quot;...&amp;quot;);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This functionality is available in the CL Tool 1.2.40 or higher.&lt;/p&gt;

&lt;p&gt;This command exports metadata objects with all of its dependencies. The &lt;code&gt;tokenFile&lt;/code&gt; is a file where the import token will be stored (you&amp;#8217;ll need it!). In &lt;code&gt;objectIDs&lt;/code&gt; you will paste the comma separated list of the metadata object IDs. The Object ID is a number which is located on the end of i.e. report URL, as you will see below.&lt;/p&gt;

&lt;p&gt;Remember that before the &lt;code&gt;ExportMetadataObjects&lt;/code&gt; you must use the &lt;code&gt;UseProject&lt;/code&gt; or the &lt;code&gt;OpenProject&lt;/code&gt; command to open the source/master project.&lt;/p&gt;

&lt;p&gt;If you are not familiar with the CL tool, choose the second option. You will need to go to the grey pages partial metadata export section which is located in the following url:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/maintenance/partialmdexport&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here you can select the metadata objects that you would like to export based on it&amp;#8217;s uri.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/8.png' alt='Object uri' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Wait a second! Where can we find the object uri? It can be found in the url address. For example, if you copy the end of the open report url address, you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/gdc/md/&amp;lt;project-id&amp;gt;/obj/&amp;lt;object-id&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The object metadata information is stored in this url.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; When you use CL Tool for migration, you have to specify &lt;code&gt;&amp;lt;object-id&amp;gt;&lt;/code&gt;, but when you want to do the same via grey pages you must specify the uri, which is the part of the url as you can see above.&lt;/p&gt;

&lt;p&gt;In this example, the report metadata contains the author, title, uri etc. See the metadata page below, in our example ID of the exported object is :&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/5.png' alt='Export' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Now, just simply paste the uri (you can paste multiple uris, one on each line) into the text input field and submit the request. The task that is invoked by you will generate an import token. You&amp;#8217;ll need to store it somewhere in order to import the report.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/6.png' alt='Export' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h2 id='importing_objects'&gt;Importing objects&lt;/h2&gt;

&lt;p&gt;It’s time to import our exported objects. Let&amp;#8217;s see how it can be done with the CL Tool and with the grey pages. With CL Tool, use the &lt;code&gt;ImportMetadataObjects&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UseProject(fileName=&amp;quot;...&amp;quot;);&lt;/code&gt;&lt;br /&gt;&lt;code&gt;ImportMetadataObjects(tokenFile=&amp;quot;...&amp;quot;, overwrite=&amp;quot;&amp;lt;true|false&amp;gt;&amp;quot;, updateLDM=&amp;quot;&amp;lt;true|false&amp;gt;&amp;quot;);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The command imports metadata objects from the token. The &lt;code&gt;tokenFile&lt;/code&gt; is the file which was generated during the export. The import command has two options: &lt;code&gt;updateLDM&lt;/code&gt; - if true, the attributes, facts names and descriptions are updated. The second option is &lt;code&gt;overwrite&lt;/code&gt; - if true, the existing metadata are overwritten. Currently only &lt;code&gt;overwrite&lt;/code&gt; = true is supported.&lt;/p&gt;

&lt;p&gt;Remember that you must call the &lt;code&gt;UseProject&lt;/code&gt; or the &lt;code&gt;OpenProject&lt;/code&gt; command before the ImportMetadataObjects to specify the destination where you want to import it.&lt;/p&gt;

&lt;p&gt;If you don’t want to use the CL Tool for this purpose, you can use the grey pages. Go to the&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/maintenance/partialmdimport/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here you paste the token that was generated during the export. (see the screenshot below)&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/7.png' alt='Export' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;After submitting, you&amp;#8217;ll see the link that takes you to the page with the import task status. Here you can see if the import was successful or if something went wrong. If the import was successful, you can log into the HR Demo Copy project, go to the Reports section and check if the report is there.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/migrating-metadata/9.png' alt='Export' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As you can see the report was successfully migrated from one project to another. Remember that export/import should be done using one user account.&lt;/p&gt;

&lt;p&gt;So, that’s the selected object migration. Isn’t it easy?! Do you like it? Let us know what you think!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/21MUyyej2Wc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/09/26/Migrating-Objects-between-Projects</feedburner:origLink></entry>
 
 <entry>
   <title>Setting up the Notifications using API</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/KlTSJWltxmo/Notifications-API" />
   <updated>2011-09-13T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/09/13/Notifications-API</id>
   <content type="html">&lt;h1 id='setting_up_the_notifications_using_api'&gt;Setting up the Notifications using API&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi everyone! Today we&amp;#8217;ll take a look at a new feature that helps you being up-to-date with your data. Cory has already mentioned it in the end of his &lt;a href='http://www.gooddata.com/blog/building-an-app-part-2'&gt;Building an Analytics App&lt;/a&gt; post. If you want to know what&amp;#8217;s going on in your Analytics App but don&amp;#8217;t want to login to GoodData every time you want to check your KPIs, then the Notifications feature is a must have.&lt;/p&gt;

&lt;p&gt;How do GoodData Notifications work? You set the condition for a metric (i.e. number of Chatter posts per Opportunity &amp;lt; 16 ). Every time the condition is fulfilled, the application sends the notification to the specified channel. The specified channel can be for example the SalesForce Chatter or Twilio, for example.&lt;/p&gt;

&lt;h2 id='using_the_gooddata_api_via_rest_client'&gt;Using the GoodData API via REST Client&lt;/h2&gt;

&lt;p&gt;Before we start setting up new notifications, we will show you how to easily work with our API. For this purpose you can use the &lt;a href='https://addons.mozilla.org/en-US/firefox/addon/restclient/'&gt;Rest Client&lt;/a&gt; for Firefox that is extension for managing API requests.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/rest-client-addon.png' alt='REST Client' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Remember that you have to be logged into GoodData to use API. It is possible to log in via the UI or on&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://&amp;lt;hostname&amp;gt;/gdc/account/login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;which is the authentication page of the API. See the screenshot below. The REST Client picks up the authentication (both from &lt;code&gt;/gdc/account/login&lt;/code&gt; and from the UI) so you can log in just once. Follow the process that is shown below to set up new notification.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/login-page-api.png' alt='Grey Pages Login' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h2 id='introducing_the_notification_api'&gt;Introducing the Notification API&lt;/h2&gt;

&lt;p&gt;So, you want to start using the Notifications. That means you will need to set it up correctly. The Notifications API consists of two REST resources - Channel Configuration and Subscription Configuration. The Channel defines where the notifications will be sent to and the Subscription Configuration contains details about what and how often will the notifications be sent.&lt;/p&gt;

&lt;p&gt;The Channel Configuration is located on following URL&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://&amp;lt;hostname&amp;gt;/gdc/account/profile/&amp;lt;profile&amp;gt;/channelConfigurations&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You have to use your profile ID in the request URL. This doesn&amp;#8217;t work with profile Email.&lt;/p&gt;

&lt;p&gt;and is used to configure delivery channels. GoodData currently supports two Notifications Channels - SalesForce Chatter and Twilio. To configure the notification that will appear on your SalesForce Chatter, you need to POST the payload that is similar to what is shown below.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
   &lt;span class='s2'&gt;&amp;quot;channelConfiguration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;configuration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;sfdcChatterConfiguration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;your@email&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;passwordSecurityToken&amp;quot;&lt;/span&gt;
         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;SFDC Channel&amp;quot;&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
   &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;As you can see you have to specify your SFDC username and password. The password is a combination of your SFDC password and generated security token.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s see the picture below and learn how it works with the REST Client for Firefox. You have to define request type, request url, set the header content type to &lt;code&gt;application/json&lt;/code&gt;, and paste the request body with json file as we defined it above. Then you can send the request. If everything is correct, you will receive &lt;code&gt;201 Created&lt;/code&gt; HTTP status.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/rest-client.png' alt='REST Client' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Otherwise, if you want to set up Twilio as a channel, your POST should look something like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
   &lt;span class='s2'&gt;&amp;quot;channelConfiguration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;configuration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;twilioSmsConfiguration&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;AUTH TOKEN&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;from&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;+14086457515&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;to&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;+420724000000&amp;quot;&lt;/span&gt;
         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;Twilio Title&amp;quot;&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
   &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To use Twilio for the notifications, you need to define your Twilio username, password, source phone number and finally phone number the notification will be sent to.&lt;/p&gt;

&lt;h2 id='setting_up_the_subscription'&gt;Setting up the Subscription&lt;/h2&gt;

&lt;p&gt;So, we&amp;#8217;ve set up the channel and now it&amp;#8217;s time to move on to the second step of configuration. We&amp;#8217;ll need to specify the notification condition, message and some other details. The Subscription Configuration resource is located on&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://&amp;lt;hostname&amp;gt;/gdc/projects/&amp;lt;project&amp;gt;/users/&amp;lt;user&amp;gt;/subscriptions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and we will set it up once again by POSTing following payload (sure not exactly this one):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
   &lt;span class='s2'&gt;&amp;quot;subscription&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;triggers&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;
         &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;timerEvent&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
               &lt;span class='s2'&gt;&amp;quot;cronExpression&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;0 0/5 * * * *&amp;quot;&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;condition&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;condition&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;expression&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;f:executeMetric(&amp;#39;/gdc/md/ChatterDemo/obj/130001729&amp;#39;) &amp;lt; 16&amp;quot;&lt;/span&gt;
         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;expression&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;Average Chatter posts per Opportunity has fallen to ${f:executeMetric(&amp;#39;/gdc/md/ChatterDemo/obj/130001729&amp;#39;)} ...&amp;quot;&lt;/span&gt;
         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;channels&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;/gdc/account/profile/1/channelConfigurations/4e313f3d300406ad568d3bec&amp;quot;&lt;/span&gt;
      &lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;:{&lt;/span&gt;
         &lt;span class='s2'&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class='ss'&gt;:&amp;quot;Avg Posts per Oppty &amp;lt; 16&amp;quot;&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
   &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now let&amp;#8217;s describe the file above. First part of config file describes the triggers. It&amp;#8217;s possible to set up multiple triggers, but in this moment only the timerEvent is supported. The timerEvent needs to have a &lt;a href='http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html'&gt;CRON expression&lt;/a&gt; defined. The granularity of notification is driven by platform configuration. In other words, even if a user specifies that he or she wants to receive a notification every minute, the user will probably receive notifications every 15 minutes (depends on configuration). It&amp;#8217;s also possible to specify a timezone by adding &amp;#8220;timezone&amp;#8221;:&amp;#8221;yourtimezone&amp;#8221; to the &lt;code&gt;timerEvent&lt;/code&gt; element. Timezone format is described &lt;a href='http://download.oracle.com/javase/6/docs/api/java/util/TimeZone.html'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As we mentioned earlier, the notification is sent only if the &lt;code&gt;condition&lt;/code&gt; is fulfilled. The condition is based on a &lt;a href='http://commons.apache.org/jexl/'&gt;JEXL&lt;/a&gt; expression that has to result in a true/false value. In our example &lt;code&gt;/gdc/md/ChatterDemo/obj/130001729 &amp;lt; 16&lt;/code&gt; means that condition is true if the metric (which is identified by unique ID) is smaller than 16.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;template&lt;/code&gt; describes the notification message, that contains the JEXL template with the metric value. The &lt;code&gt;channels&lt;/code&gt; element describes which channel the notification will be sent to, based on the configuration. Finally, the &lt;code&gt;meta&lt;/code&gt; element contains the title of the notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You can also apply GET, PUT or DELETE to the configuration resource to retrieve, update or delete the configuration. Also, all requests has to contain Content-type: application/json request header.&lt;/p&gt;

&lt;h2 id='the_result'&gt;The Result&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ve set everything up, so now it&amp;#8217;s time to see the result. Every time the &lt;code&gt;Average Posts / Opportunity&lt;/code&gt; falls below 16 the notification will be sent to our SFDC Chatter. Check out the screenshot below!&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/notification.jpg' alt='Metric falls below 16' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The notification is sent:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/notification2.jpg' alt='The Notification is sent' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Yes, That&amp;#8217;s it. I hope you will be up-to-date with your data after reading the blogpost!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/KlTSJWltxmo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/09/13/Notifications-API</feedburner:origLink></entry>
 
 <entry>
   <title>Incremental Data Loading</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/IHcNiAsmOzY/Incremental-data-loading" />
   <updated>2011-08-30T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/08/30/Incremental-data-loading</id>
   <content type="html">&lt;h1 id='incremental_data_loading'&gt;Incremental Data Loading&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, you want to do some analytics. You will need to have complete and updated data. That means continuously loading your data which can seem difficult. However, this process can be fully automated using the GoodData CL Tool. Imagine you have a lot of data. It would be nonsense to do the full data load every time you want to update it. It would take too much time and can be very expensive. So what do we do? The solution is to use incremental data loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Incremental Data Loading Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Incremental data loading is a feature which is already implemented in the GoodData CL Tool. You can run it by adding parameter into the TransferData(incremental=”true”) command. When you are uploading data using the Incremental Data Loading, the existing data won’t be deleted. The existing data will be merged/replaced with the new data that are being uploaded and new data will be appended to the existing data. The merging/replacing existing data with the new records is possible thanks to the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; of every record. How does it work?&lt;/p&gt;

&lt;p&gt;The data that is being uploaded may contain records with the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; value that already exists in your project. As you probably know, the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; is a CL Tool&amp;#8217;s description of a column of your dataset (alternative to &lt;code&gt;ATTRIBUTE&lt;/code&gt; and &lt;code&gt;FACT&lt;/code&gt;). The data loading script simply compares the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; of existing records and replaces them with the new values. However, please keep in mind that if the incremental parameter is false, data loading script will delete all of the existing data and then load new data that you want to upload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting up the CONNECTION_POINT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s describe the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; functionality in more detail. The &lt;code&gt;CONNECTION_POINT&lt;/code&gt; is basically the primary key of the data set. It can provide connections with other data sets (through the &lt;code&gt;REFERENCE&lt;/code&gt; ldmType). If you are not familiar with joining data sets together, you can learn more about it &lt;a href='http://developer.gooddata.com/blog/2011/06/22/useCases-part2/'&gt;here&lt;/a&gt; or see the XML schema example below.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;schema&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;storeid&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;StoreID&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;CONNECTION_POINT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store_name&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store name&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;employees&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Employees&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/schema&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The basic condition is to set it up correctly. Every single record of your data must have a unique value of the &lt;code&gt;CONNECTION_POINT&lt;/code&gt;. If it doesn’t, records with the same value will be replaced during the loading. That means when you have three rows with the same CONNECTION_POINT value only the record that was uploaded last will be in your data. (replacing those two rows with the same value that was uploaded before the last record) As you can see on the example above, where the &lt;code&gt;StoreID&lt;/code&gt; column is the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; of the dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to use Incremental data loading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s see two examples of how to use the incremental data loading. As we said in the beginning, you are probably in a situation where you need to update the data daily and you don’t want to keep uploading all of your data repeatedly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1st Example (Loading data for the last three days)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first use case is simple. You have the analytics application and upload the data 3 days back till today every day. So every day you use incremental data loading that includes the data from the last three days. What will the script do during the data load in this case?&lt;/p&gt;

&lt;p&gt;It loads the data and if some of it already exists (has the same &lt;code&gt;CONNECTION_POINT&lt;/code&gt; value) it will replace it with the new values. If the records you are uploading are completely new, the script will append them.&lt;/p&gt;

&lt;p&gt;This use case has another advantage. If the data load fails on any given day, the records will be added the next day. In this situation, the problem will be if data load fails 3 days in a row. If this occurs, the data will be missing from the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2nd Example (Google Analytics)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another example is little bit more complex. It’s based on the specific behavior of Google Analytics. The most recent data from Google Analytics isn&amp;#8217;t usually up to date, so typically you will need to load the data from the day before everyday.&lt;/p&gt;

&lt;p&gt;For example, yesterday we used the Google Analytics API to get the page views and visits by referrers. The API may return something like this:&lt;/p&gt;

&lt;p&gt;2011-08-10,Google,500,30&lt;br /&gt;2011-08-10,Bing,50,15&lt;/p&gt;

&lt;p&gt;Now, by adding the unique connection point to the records, our data load will look something like this:&lt;/p&gt;

&lt;p&gt;ea3d273d6296684da21d3dc2aa82d0b7,2011-08-10,Google,500,30&lt;br /&gt;f4583c4214d22677d991e25d041336ea,2011-08-10,Bing,50,15&lt;/p&gt;

&lt;p&gt;In this case, the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; is MD5 hash which is computed from the attributes and its values. It can be easily done with the &lt;code&gt;IDENTITY&lt;/code&gt; &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element. If you add the &lt;code&gt;IDENTITY&lt;/code&gt; transformation to the dataset, the column that is transformed is automatically filled with the MD5 hash of every non-fact column (attributes, labels etc.). The transformation column is added to the dataset and uploaded regularly. See the definition of the transformation column on the example below.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;schema&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;storeid&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;StoreID&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;CONNECTION_POINT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;transformation&amp;gt;&lt;/span&gt;IDENTITY&lt;span class='nt'&gt;&amp;lt;/transformation&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  ...
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/schema&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The next day, we use the same query and it returns larger values which is normal because yesterday’s data may not have been completed. The result will be:&lt;/p&gt;

&lt;p&gt;2011-08-10,Google,509,33&lt;br /&gt;2011-08-10,Bing,52,19&lt;/p&gt;

&lt;p&gt;When we add our hash based &lt;code&gt;CONNECTION_POINT&lt;/code&gt; to the data once again, we will get:&lt;/p&gt;

&lt;p&gt;ea3d273d6296684da21d3dc2aa82d0b7,2011-08-10,Google,509,33&lt;br /&gt;f4583c4214d22677d991e25d041336ea,2011-08-10,Bing,52,19&lt;/p&gt;

&lt;p&gt;Finally, we&amp;#8217;ll use the incremental data load to update yesterday&amp;#8217;s incomplete data. This is very useful if you need to replace incomplete data with complete data.&lt;/p&gt;

&lt;p&gt;See you next time!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/IHcNiAsmOzY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/08/30/Incremental-data-loading</feedburner:origLink></entry>
 
 <entry>
   <title>Building a Project in GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/BDg25q6m31I/how-to-create-project-in-gooddata" />
   <updated>2011-08-17T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/08/17/how-to-create-project-in-gooddata</id>
   <content type="html">&lt;h1 id='building_a_project_in_gooddata'&gt;Building a Project in GoodData&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So you want to start analyzing your business data using the GoodData Platform and don&amp;#8217;t know where to start. Well, you have two different options to choose from to help you get started - use &lt;strong&gt;Apps&lt;/strong&gt; that are based on prepared project templates or build a &lt;strong&gt;custom project&lt;/strong&gt;. If you are not sure about how to start building your own custom project on the GoodData Platform, use our &lt;a href='http://www.gooddata.com/apps'&gt;Apps&lt;/a&gt; or read about &lt;a href='http://www.gooddata.com/blog/building-an-app-part-1'&gt;building an app&lt;/a&gt; non-programmatically. This is very easy and you can start analyzing your data within minutes. The second option is more technical and powerful.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s move on how to create a custom project. Imagine you have multiple data sources that you want to analyze using the GoodData Platform. Is it possible? Yes, it is. So, what are the steps to be taken?&lt;/p&gt;

&lt;p&gt;You will start with defining a Logical Data Model. The Logical Data Model describes the structure of the data you&amp;#8217;ll report on. It contains one or more datasets that can be &lt;a href='http://developer.gooddata.com/gooddata-cl/examples/hr/'&gt;connected together&lt;/a&gt;. What is in a dataset? Each dataset consists of Facts and Attributes. Facts are numbers that we will aggregate later in metrics. Attributes are names and properties that describe your Facts. For example you can compute the SUM of the Payment fact and slice it by the Department attribute in the &lt;a href='http://developer.gooddata.com/gooddata-cl/examples/hr/'&gt;HR demo&lt;/a&gt; that is outlined on the figure below. &lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/	2011-06-21-new.ldm.png' alt='Logical Data Model Example' /&gt;&lt;/center&gt;
&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;The big advantage of GoodData platform is the fact that the Physical Data Model (database tables and columns) is automatically generated from the Logical Data Model. Read more in &lt;a href='http://developer.gooddata.com/blog/2011/07/26/MAQL-description/'&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you define a Logical Data Model, you will need to load your data in your new project. You can use the &lt;strong&gt;CL Tool&lt;/strong&gt; for the data loading. The CL Tool is powerful command-line tool for managing GoodData projects. It automates all common tasks that you&amp;#8217;ll need to perform on your project including the LDM creation, data loading, user provisioning etc. Read &lt;a href='http://developer.gooddata.com/gooddata-cl/cli-commands.html'&gt;this documentation&lt;/a&gt; to find out how to Create, Update and &lt;a href='http://developer.gooddata.com/blog/2011/06/06/project-cloning/'&gt;Clone your Project&lt;/a&gt;, or upload the data.&lt;/p&gt;

&lt;p&gt;The CL Tool is built on top of connectors that allow you to transfer data from CSV files, database (JDBC) or many SaaS applications connectors (Google Analytics, Pivotal Tracker, etc.). Find out more about basic usage of the CL Tool in one of our &lt;a href='http://developer.gooddata.com/blog/2011/06/22/useCases-part1/'&gt;previous blogpost&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have your data inside the platform you are ready to create metrics. Metrics and Attributes are the foundation of every report that you build. Metrics are, as mentioned above, aggregated (SUM, AVG, MIN, MAX) Facts. We developed powerful multidimensional query language called MAQL that you can use to create any metric you&amp;#8217;ll need. Read &lt;a href='http://developer.gooddata.com/docs/maql.html'&gt;the metrics documentation&lt;/a&gt; or &lt;a href='http://developer.gooddata.com/blog/2011/07/29/Analyzing-Change/'&gt;snapshotting blogpost&lt;/a&gt; to get more insight.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/Building-Project-On-Platform-Metrics.png' alt='Creating Metrics' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;This brings us to the key part of every project - &lt;strong&gt;Reports&lt;/strong&gt; and &lt;strong&gt;Dashboards&lt;/strong&gt;. Reports are built on top of three important concepts: aggregation (metrics) by attributes, filtering and visualization. Every time you build a report you have to specify WHAT (which &lt;a href='http://developer.gooddata.com/docs/maql.html'&gt;metric&lt;/a&gt;) you want to analyze, and HOW (attribute) you want to slice it. See the picture below. The Filter button helps you to filter your report data.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/Building-Project-On-Platform-Report.png' alt='Building Report' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The last but not least step is to choose a suitable visualization for your aggregated data. GoodData offers a lot of visualization options including pie charts, bar charts, pivot tables and so on. You can also use the custom number formatting to visualize your data. See &lt;a href='http://developer.gooddata.com/blog/2010/10/19/numbers-trends-on-dashboard/'&gt;this example&lt;/a&gt; and &lt;a href='https://secure.gooddata.com/docs/html/reference.guide.reportoptions.formatting.html'&gt;the documentation&lt;/a&gt; for more information about this topic.&lt;/p&gt;

&lt;p&gt;The final step is to organize your reports in a dashboard that presents them to a specific audience (e.g. your CEO). The best practice is to identify 3-5 most important company&amp;#8217;s KPIs (metrics) and put them on the first tab as headline report (one single number). The subsequent tabs usually show the KPIs sliced by time, departments etc. See the marketing dashboard example below.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/Building-Project-On-Platform-Dashboard.png' alt='Dashboard' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The dashboards and reports are often embedded into the web applications and portals that your users frequently use. You&amp;#8217;ll first need to create and invite your users to the new GoodData project. It can also be &lt;a href='http://developer.gooddata.com/blog/2011/07/14/add-user-to-project/'&gt;done programmatically using the CL Tool&lt;/a&gt;. Then you can embed the dashboards and reports to your existing web app. Check out &lt;a href='http://developer.gooddata.com/blog/2011/06/29/filtering-embedded-reports/'&gt;blogpost about embedding&lt;/a&gt;. You can even setup a Single Sign On (SSO) mechanism that will allow your users to log into their GoodData project once with your web app&amp;#8217;s credentials.&lt;/p&gt;

&lt;p&gt;Now, let&amp;#8217;s sum up the whole process once again. To create an analytical project you have to do following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Develop Logical Data Model&lt;/li&gt;

&lt;li&gt;ETL process (Getting your data in)&lt;/li&gt;

&lt;li&gt;Create metrics&lt;/li&gt;

&lt;li&gt;Create reports&lt;/li&gt;

&lt;li&gt;Create dashboards&lt;/li&gt;

&lt;li&gt;Embed reports and dashboards&lt;/li&gt;

&lt;li&gt;Maintain your project: e.g. add users to your project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That&amp;#8217;s it. Start building your own project and let us know how it worked for you!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/BDg25q6m31I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/08/17/how-to-create-project-in-gooddata</feedburner:origLink></entry>
 
 <entry>
   <title>Analyzing Change</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/Y-mlINMsGE0/Analyzing-Change" />
   <updated>2011-07-29T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/07/29/Analyzing-Change</id>
   <content type="html">&lt;h1 id='analyzing_change'&gt;Analyzing Change&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;) &amp;amp; ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Analyzing the latest and the greatest data in GoodData is easy. You simply add up all sales opportunities in a revenue metric and then slice the number by sales stages, status, region, sales rep, or whatever you like. Sometimes your users start asking questions like: “What was my pipeline at the beginning of this quarter and how it has improved since then?”. You quickly realize that you need to keep the history of your opportunities and understand how any opportunity changed over time.&lt;/p&gt;

&lt;p&gt;This article introduces the analytic technique that we call &lt;strong&gt;snapshotting&lt;/strong&gt;. We’ll stay in the realm of sales and describe the snapshotting on a simple sales automation example. Welcome to the world of opportunities, sales stages, and &lt;strong&gt;change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Keep in mind that you’ll hear similar questions from your help desk guy, quality guy or a head of your engineering. Snapshotting help you in these cases as well. Follow this article and substitute case, bug or feature for the opportunity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sales Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sales Analytics is all about sales opportunities that are generated by your business activities. Each opportunity has a status that describes if the opportunity is &lt;strong&gt;Open&lt;/strong&gt; (Pipeline), &lt;strong&gt;Won&lt;/strong&gt; (Revenue), or &lt;strong&gt;Lost&lt;/strong&gt; (Lost Revenue).&lt;/p&gt;

&lt;p&gt;Now our hypothetical VP of Sales, lets call him Michael asks his million dollars question: “What was my pipeline at the beginning of this quarter and how it has improved since then?”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snapshotting Basics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Snapshotting is straightforward and easy to use technique that helps answering the Michael&amp;#8217;s question. The key idea is that we keep transferring all opportunities from your CRM to GoodData every week (or day or month - it depends on your requirements). We call the weekly set of opportunities the snapshot. Each snapshot is associated with a date and an unique ID.&lt;/p&gt;

&lt;p&gt;So if we have a project that accumulates snapshots for 118 weeks, most of our opportunities will be duplicated 118 times in the project. Few of them that have been created after we started snapshotting have less than 118 versions. Each version is associated with a snapshot date (perhaps Monday of each week) and the snapshot ID. It is very beneficial to use snapshot IDs in sequence without gaps. We can then simply identify previous/next snapshots as the current ID minus/plus one.&lt;/p&gt;

&lt;p&gt;And here is the first catch. A simple &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open&lt;/code&gt; metric measures your pipeline returns a number that is roughly 118 times higher than what we expect. No wonder, because we are adding up all ten versions of each opportunity. We need to be smarter here. We can define metric that shows the total amount for individual snapshot only:&lt;/p&gt;

&lt;p&gt;Pipeline [118 weeks ago]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pipeline [Now]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = 118&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nice, this was easy. But you’ll need a new metric next week and another one week after next week. A metric that returns the total amount for the last snapshot would be handy. Lets start creating such a metric with identifying the last snapshot:&lt;/p&gt;

&lt;p&gt;Snapshot [Most Recent]: &lt;code&gt;SELECT MAX(SnapshotId)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This definition sounds easy enough, however it has certain problems. Imagine that we fired a Sales Rep. John during the snapshot 25 (not nice but he well deserved it). We kept all opportunities that he has closed associated with him and re-associated all open opportunities to other sales guys.&lt;/p&gt;

&lt;p&gt;Now if we break down the Snapshot [Most Recent] metric by the SalesRep, we will see that the metric returns 118 for all Sales Reps except John who gets the Snapshot [Most Recent] = 25. This is problem because we would compute our total on the snapshot 25 for John and on the snapshot 118 for everybody else. We need to improve the definition of the Snapshot [Most Recent] metric:&lt;/p&gt;

&lt;p&gt;Snapshot [Most Recent]: &lt;code&gt;SELECT MAX(SnapshotId) BY ALL IN ALL OTHER DIMENSIONS WITHOUT PARENT FILTER&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This metric returns the MAX snapshot regardless any dimensions. The last snapshot (= 118) for all Sales Reps including John, for all regions, for all Products etc. When you add the &lt;code&gt;BY ALL IN ALL OTHER DIMENSIONS&lt;/code&gt; statement to your metric it returns the grand total (MAX) of all the time and all dimensions. It returns a constant.&lt;/p&gt;

&lt;p&gt;What is the &lt;code&gt;WITHOUT PARENT FILTER&lt;/code&gt; clause for? Imagine that you place the metric into a report that contains the &lt;code&gt;SalesRep = John&lt;/code&gt; filter. Applying this filter would lead to the same troubles that we&amp;#8217;ve eliminated with the &lt;code&gt;BY ALL IN ALL OTHER DIMENSIONS&lt;/code&gt;. The &lt;code&gt;WITHOUT PARENT FILTER&lt;/code&gt; clause simply ignores the higher level filters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Find out more examples and aggregation concepts in &lt;a href='http://developer.gooddata.com/docs/maql.html'&gt;this documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then we can use the Snapshot [Most Recent] metric in our pipeline metric and get the latest amount this way:&lt;/p&gt;

&lt;p&gt;Pipeline [Now]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = Snapshot [Most Recent]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Similarly we can compute the pipeline for the first snapshot (the oldest one). The metric is:&lt;/p&gt;

&lt;p&gt;Snapshot [Oldest]: &lt;code&gt;SELECT MIN(SnapshotId) BY ALL IN ALL OTHER DIMENSIONS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and use it in the following pipeline metric:&lt;/p&gt;

&lt;p&gt;Pipeline [Oldest]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = Snapshot [Oldest]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measuring Pipeline Change in a Quarter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The oldest and the most recent snapshots are great but we want something slightly different. We want to compute the pipeline for the first and the last snapshot in a quarter. We can achieve this by following metric definitions:&lt;/p&gt;

&lt;p&gt;Snapshot [First in Period]: &lt;code&gt;SELECT MIN(SnapshotId) BY ALL IN ALL OTHER DIMENSIONS EXCEPT SnapshotDate WITHOUT PARENT FILTER&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Snapshot [Last in Period]: &lt;code&gt;SELECT MAX(SnapshotId) BY ALL IN ALL OTHER DIMENSIONS EXCEPT SnapshotDate WITHOUT PARENT FILTER&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s focus on the &lt;code&gt;BY ALL IN ALL OTHER DIMENSIONS Except&lt;/code&gt; statement. Using this concept it allows you to compute total MAX/MIN of SnapshotId regardless any dimension but with exception of the specific attribute. The exception is an attribute after the &lt;code&gt;EXCEPT&lt;/code&gt; expression. So the resulting number is not going to be a constant anymore. It will depend on the value of the SnapshotDate. In other words this metric returns the maximum SnapshotId for the SnapshotDate period.&lt;/p&gt;

&lt;p&gt;If you put the metrics above to a report with the Snapshot Quarter, you will see the first and the last snapshot ID that we have for each quarter. See the report below:&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/min-max-snapshot.png' alt='Min and Max Snapshot in Quarter' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;So then the pipeline at the beginning of a period is:&lt;/p&gt;

&lt;p&gt;Pipeline [First in Period]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = Snapshot [First in Period]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the latest and greatest pipeline number is:&lt;/p&gt;

&lt;p&gt;Pipeline [Last in Period]: &lt;code&gt;SELECT SUM(Amount) WHERE Status = Open AND SnapshotId = Snapshot [Last in Period]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you just put these two metrics into a report with the Snapshot Quarter and you’ll get the pipeline at the beginning of each quarter and the last known pipeline each quarter.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/pipeline-change.png' alt='Pipeline Change Report' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;You can divide or subtract these numbers to get the absolute or relative growths, whatever you need&amp;#8230;Easy enough, isn’t it?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/Y-mlINMsGE0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/07/29/Analyzing-Change</feedburner:origLink></entry>
 
 <entry>
   <title>Creating Analytical Project with MAQL DDL</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/gJ7Z5eM32Z0/MAQL-description" />
   <updated>2011-07-26T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/07/26/MAQL-description</id>
   <content type="html">&lt;h1 id='creating_analytical_project_with_maql_ddl'&gt;Creating Analytical Project with MAQL DDL&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today we will show you the relationship between the GoodData Logical Data Model (LDM), Physical Data Model (PDM) and MAQL DDL language. MAQL DDL is GoodData proprietary data definition language. We will outline the basic MAQL DDL concepts in this article.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;LDM&lt;/strong&gt; (Logical Data Model) is necessary for creating your reports. It consists of attributes and facts that GoodData users add to their reports.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;PDM&lt;/strong&gt; (Physical Data Model) is used for the data storage and query. It is de-facto a DBMS schema (tables, columns, primary/foreign keys etc.).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;DLI&lt;/strong&gt; (Data Loading Interface) is used for loading data to the GoodData projects.&lt;/p&gt;

&lt;p&gt;LDM describes the logical structure of organization&amp;#8217;s data in terms like datasets, attributes and facts (check out this &lt;a href='http://developer.gooddata.com/api/maql-ddl.html'&gt;documentation&lt;/a&gt; for more info). Most analytical tools and platforms will force you to develop both LDM and PDM that are perfectly aligned. Unlike the average tools, GoodData interface with user only via the LDM. The corresponding PDM and DLI are automatically generated from the LDM. The LDM model is created and modified via the MAQL DDL language statements, that are kind of similar to the SQL DDL (Data Definition Language).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: We&amp;#8217;ll use the &amp;#8220;Employee&amp;#8221; dataset example to show you the relationship between the LDM, PDM and DLI. A similar dataset is part of the &lt;a href='http://developer.gooddata.com/gooddata-cl/examples/hr/'&gt;HR demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lets start with a simple LDM model that you can see on the figure below. As you can see, the LDM contains one fact and two attributes in a hierarchy (department and employee).&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/ldm-model.png' alt='Logical Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;As we have mentioned above, we&amp;#8217;ll use the MAQL DDL language to define the LDM. The rest (PDM and DLI) will be generated automatically via the SYNCHRONIZE MAQL DDL command.&lt;/p&gt;

&lt;p&gt;The PDM is standard DBMS schema with tables, columns, primary and foreign keys. A LDM &lt;code&gt;ATTRIBUTE&lt;/code&gt; is represented by a database table with primary key and couple text columns (one for each &lt;code&gt;LABEL&lt;/code&gt;) in the PDM. A LDM &lt;code&gt;FACT&lt;/code&gt; is mapped to a column in a PDM fact table. The figure below outlines the PDM that has been automatically generated from the LDM above.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/pdm-model.png' alt='Physical Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;The last piece of the puzzle is the DLI that is necessary for data loading. GoodData platform loads data in self-describing packages. The data package is a ZIP archive that contains the data (delimited file) and a manifest that describes how the data map to the project&amp;#8217;s LDM and PDM. The figure below shows the data file only. As you can see this is de-normalized (flattened &lt;code&gt;d_employee_department&lt;/code&gt; and &lt;code&gt;f_employee&lt;/code&gt; PDM tables) version of the PDM.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/data-template.png' alt='Data Template' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;Now, we&amp;#8217;ll inspect the MAQL DDL statements that create the LDM model above. We&amp;#8217;ll create the Employee dataset with the Department and Employee attributes and the Salary fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Employee dataset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we have to create the Employee dataset. Here is the corresponding MAQL statement:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE DATASET {dataset.employee} VISUAL(TITLE &amp;quot;Employee&amp;quot;);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That creates the Employee dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Salary fact&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE FACT {fact.employee.salary} VISUAL(TITLE &amp;quot;Salary&amp;quot;) AS {f_employee.f_salary};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER DATASET {dataset.employee} ADD {fact.employee.salary};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first statement creates new &lt;code&gt;Salary&lt;/code&gt; fact (LDM) and the corresponding &lt;code&gt;{f_salary}&lt;/code&gt; column in the &lt;code&gt;f_employee&lt;/code&gt; table (PDM). Remember that the fact is represented as a database column.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All PDM tables, columns, keys etc. are automatically generated after calling the &lt;code&gt;SYNCHRONIZE&lt;/code&gt; MAQL DDL command that is usually the last command of a MAQL DDL script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Employee attribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE ATTRIBUTE {attr.employee.id} VISUAL(TITLE &amp;quot;Employee&amp;quot;) AS KEYS {f_employee.id} FULLSET;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER ATTRIBUTE {attr.employee.id} ADD LABELS {label.employee.ssn} VISUAL(TITLE &amp;quot;SSN&amp;quot;) AS {f_employee.nm_ssn};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER ATTRIBUTE {attr.employee.id} ADD LABELS {label.employee.name} VISUAL(TITLE &amp;quot;Name&amp;quot;) AS {f_employee.nm_name};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER DATASET {dataset.employee} ADD {attr.employee.id};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first command line creates the LDM attribute named Employee. The LDM attribute maps to a PDM table that has the primary key &lt;code&gt;{f_employee.id}&lt;/code&gt; (FULLSET). We can also add the foreign key, but we are not going to do it so right now. Stay tuned, we will show it later. As mentioned above, the attribute is defined as a PDM table. The attribute itself is the auto-generated ID &lt;code&gt;f_employee.id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second and the third row add labels to the Employee attribute. As you&amp;#8217;ve guessed already, labels are text representations of the attribute. For example, the Employee attribute has two: the SSN and the Name. Later you&amp;#8217;ll be able to choose which label is more suitable for your report. Both labels and ID map to the columns in PDM table (&lt;code&gt;{id}&lt;/code&gt;, &lt;code&gt;{nm_ssn_}&lt;/code&gt; and &lt;code&gt;{nm_name}&lt;/code&gt;). You&amp;#8217;ll see these names later in the DLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Department attribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, we will repeat the exercise and create the Department attribute. The only difference is that we&amp;#8217;ll create the foreign key to the &lt;code&gt;f_employee&lt;/code&gt; table now. Note that the first MAQL DDL statement contains two keys. The first one &lt;code&gt;d_employee_department.id&lt;/code&gt; is the primary key and the second one &lt;code&gt;f_employee.department_id&lt;/code&gt; is the foreign key that ties the &lt;code&gt;d_employee_department&lt;/code&gt; table to the &lt;code&gt;f_employee&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE ATTRIBUTE {attr.employee.department} VISUAL(TITLE &amp;quot;Department&amp;quot;) AS KEYS {d_employee_department.id} FULLSET, {f_employee.department_id};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER ATTRIBUTE {attr.employee.department} ADD LABELS {label.employee.department.name} VISUAL(TITLE &amp;quot;Department&amp;quot;) AS {d_employee_department.nm_department};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALTER DATASET {dataset.employee} ADD {attr.employee.department};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the second line of the script, we again added the label to the Department attribute. Label is defined as &lt;code&gt;nm_department&lt;/code&gt; column in the &lt;code&gt;{d_employee_department}&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Finally we add the Department attribute to the Employee dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating / Synchronizing PDM and DLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the magic statement that generates the PDM and the DLI.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SYNCHRONIZE {dataset.employee};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Remember that SYNCHRONIZE command will erase all data and require to load it back.&lt;/p&gt;

&lt;p&gt;The figure below describes the relationship between the MAQL DDL, LDM, PDM and DLI.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/maql-generating.png' alt='Logical Data Model' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Loading data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have called the SYNCHRONIZE command and we&amp;#8217;ve ended up with an empty GoodData project. The last step is to populate it with some useful data. We can use the DLI REST API to do it. The DLI API is a combination of a private WebDav storage where we upload the self-describing data package and a simple asynchronous call (&lt;code&gt;/etl/pull&lt;/code&gt;) that starts the data loading process. You find more in the &lt;a href='http://developer.gooddata.com/api/#data'&gt;DLI documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The self-describing data package is a ZIP archive, that contains the data file with predefined columns and a simple manifest that describes the mapping between the data file and the project&amp;#8217;s PDM. The data package template reside on this URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;your-project-number&amp;gt;/ldm/singleloadinterface/dataset.&amp;lt;your-dataset-name&amp;gt;/template&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can simply download the template, unzip it, populate the data file with your data (you&amp;#8217;ll need to preserve the header row and the column sequence), re-pack it, upload it to the DLI API&amp;#8217;s WebDav location, and call the &lt;code&gt;etl/pull&lt;/code&gt; API to start the asynchronous data loading process. That&amp;#8217;s all about the MAQL DDL, PDM, DLI and LDM for today. See you next time!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/gJ7Z5eM32Z0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/07/26/MAQL-description</feedburner:origLink></entry>
 
 <entry>
   <title>Adding User to Project Programmatically</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/7UhVbG8lnAM/add-user-to-project" />
   <updated>2011-07-14T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/07/14/add-user-to-project</id>
   <content type="html">&lt;h1 id='adding_user_to_project_programmatically'&gt;Adding User to Project Programmatically&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href='https://github.com/gooddata/GoodData-CL/downloads'&gt;CL Tool 1.2.35&lt;/a&gt; adds a new &lt;code&gt;AddUsersToProject&lt;/code&gt; command that allows you to programmatically add an existing user (previously created by the &lt;code&gt;CreateUser&lt;/code&gt; command). No confirmation e-mails are required. The user who is adding new users must be the admin in the project where the new users are added. Moreover the user must be the domain admin. Let us know at &lt;a href='mailto:support@gooddata.com'&gt;support@gooddata.com&lt;/a&gt; if you need your own domain.&lt;/p&gt;

&lt;p&gt;Once your account is associated with the domain, you can simply run the command from a CL Tool script:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CreateUser(domain="MYDOMAIN", username="admin@domain.com", password="secret", firstName="John", lastName="Doe", company="John.Doe@acme.com", ssoProvider="SALESFORCE", usersFile="users.txt", append="true");&lt;/code&gt;&lt;/p&gt;
&lt;code&gt;AddUsersToProject(usersFile="users.txt", role="DASHBOARD ONLY");&lt;/code&gt;
&lt;p&gt;Each new user created by the &lt;code&gt;CreateUser&lt;/code&gt; command is identified by an URI that can be accumulated in the &lt;code&gt;usersFile&lt;/code&gt;. The &lt;code&gt;usersFile&lt;/code&gt; can be overwritten (&lt;code&gt;append="false"&lt;/code&gt;) or appended (&lt;code&gt;append="true"&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The users represented by the URIs in the &lt;code&gt;usersFile&lt;/code&gt; can be added to an existing project using the &lt;code&gt;AddUsersToProject&lt;/code&gt; command. This command requires a project context (_CreateProject_, &lt;em&gt;OpenProject&lt;/em&gt;, &lt;em&gt;UseProject&lt;/em&gt; above). Then it wants the &lt;code&gt;usersFile&lt;/code&gt; that contains a user URI on each line and the &lt;code&gt;role&lt;/code&gt; parameter that specifies the role (_admin_, &lt;em&gt;editor&lt;/em&gt;, &lt;em&gt;dashboard only&lt;/em&gt;) that all users will have in the project.&lt;/p&gt;

&lt;p&gt;As always the &lt;code&gt;AddUsersToProject&lt;/code&gt; command invokes corresponding REST API. You can always check out the API invocation in the &lt;a href='https://github.com/gooddata/GoodData-CL/blob/master/backend/src/main/java/com/gooddata/integration/rest/GdcRESTApiWrapper.java'&gt;CL tool source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let us know what you think!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/7UhVbG8lnAM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/07/14/add-user-to-project</feedburner:origLink></entry>
 
 <entry>
   <title>Defining column with transformation element</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/_klSaA6tb44/transformation-element-usage" />
   <updated>2011-07-11T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/07/11/transformation-element-usage</id>
   <content type="html">&lt;h1 id='defining_column_with_transformation_element'&gt;Defining column with transformation element&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka (&lt;a href='http://twitter.com/jirtob'&gt;@jirtob&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you certainly know when you work with GoodData CL tool for managing projects and data you have to create schema &lt;code&gt;XML config file&lt;/code&gt; for defining your dataset. You know there are several elements associated with column element for example &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ldmType&amp;gt;&lt;/code&gt; and there is also &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element. What would be probably new for you is how you can also use this element for defining the column.&lt;/p&gt;

&lt;p&gt;The main purpose of this blogpost is to show you an option of using &lt;code&gt;JAVA&lt;/code&gt; language syntax inside &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element and create &amp;#8220;computed value&amp;#8221; in column based on other columns in your &lt;code&gt;XML config file&lt;/code&gt;. For basic example imagine you want to join together user&amp;#8217;s &lt;code&gt;First name&lt;/code&gt; and &lt;code&gt;Last name&lt;/code&gt; into one &lt;code&gt;Name&lt;/code&gt; column. You can join these two text fields and the rows in column is automatically filled by &amp;#8220;computed value&amp;#8221; with the definition in &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element. You should use the &lt;code&gt;&amp;lt;![CDATA[...]]&amp;gt;&lt;/code&gt; element inside because of non-XML code. As you can see below:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;transformation&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;![CDATA[ lastname+&amp;quot;, &amp;quot;+firstname]]&amp;gt;&lt;/span&gt;&lt;span class='nt'&gt;&amp;lt;/transformation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The feature loads all columns by name and you can then use them for creating &amp;#8220;computed value&amp;#8221;. This is done by &lt;code&gt;JEXL technology&lt;/code&gt; and you can use any of &lt;a href='http://commons.apache.org/jexl/reference/syntax.html'&gt;JEXL statements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More detailed example using Java&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you can see below we have &lt;code&gt;XML config file&lt;/code&gt; for the Opportunity dataset which is prepared for SugarCRM Analytics. Besides &amp;#8220;standard&amp;#8221; column &lt;code&gt;stage&lt;/code&gt; (won&amp;#8217;t be uploaded because of &lt;code&gt;IGNORE&lt;/code&gt; ldmType) which defines stage of every sales opportunity (final stage would acquire value &lt;code&gt;Open&lt;/code&gt;, &lt;code&gt;Closed Won&lt;/code&gt; and &lt;code&gt;Closed Lost&lt;/code&gt;) we&amp;#8217;ve prepared also three columns which will be computed from the &lt;code&gt;stage&lt;/code&gt; column using &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;schema&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Opportunity&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
     ...
     ...
      &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;stage&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Opportunity Type&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;IGNORE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;status&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Opportunity Status&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Opportunity&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;transformation&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;![CDATA[ (stage.indexOf(&amp;quot;Closed&amp;quot;)&amp;gt;=0)?((stage.indexOf(&amp;quot;Won&amp;quot;)&amp;gt;=0)?(&amp;quot;Won&amp;quot;):(&amp;quot;Lost&amp;quot;)):(&amp;quot;Open&amp;quot;)]]&amp;gt;&lt;/span&gt;&lt;span class='nt'&gt;&amp;lt;/transformation&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;isclosed&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Opportunity Is Closed&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;transformation&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;![CDATA[(stage.indexOf(&amp;quot;Closed&amp;quot;)&amp;gt;=0)?(&amp;quot;true&amp;quot;):(&amp;quot;false&amp;quot;)]]&amp;gt;&lt;/span&gt;&lt;span class='nt'&gt;&amp;lt;/transformation&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Opportunity&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;iswon&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Opportunity Is Won&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Opportunity&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
          &lt;span class='nt'&gt;&amp;lt;transformation&amp;gt;&lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;![CDATA[(stage.indexOf(&amp;quot;Won&amp;quot;)&amp;gt;=0)?(&amp;quot;true&amp;quot;):(&amp;quot;false&amp;quot;)]]&amp;gt;&lt;/span&gt;&lt;span class='nt'&gt;&amp;lt;/transformation&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/schema&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;What we did is fill the &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element with &lt;code&gt;Java&lt;/code&gt; code that do the job. In &lt;code&gt;status&lt;/code&gt; column we would like to have the status information which could be &lt;code&gt;Won&lt;/code&gt;, &lt;code&gt;Lost&lt;/code&gt; or &lt;code&gt;Open&lt;/code&gt;. Following &lt;code&gt;Java&lt;/code&gt; code secure that&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;![CDATA[ (stage.indexOf(&amp;quot;Closed&amp;quot;)&amp;gt;=0)?((stage.indexOf(&amp;quot;Won&amp;quot;)&amp;gt;=0)?(&amp;quot;Won&amp;quot;):(&amp;quot;Lost&amp;quot;)):(&amp;quot;Open&amp;quot;)]]&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally we&amp;#8217;ve got the &lt;code&gt;iswon&lt;/code&gt; and &lt;code&gt;isclosed&lt;/code&gt; columns that show us simple true or false values based on the &lt;code&gt;stage&lt;/code&gt; column. Here is the code with an easy condition&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;![CDATA[(stage.indexOf(&amp;quot;Closed&amp;quot;)&amp;gt;=0)?(&amp;quot;true&amp;quot;):(&amp;quot;false&amp;quot;)]]&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;respectively&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;![CDATA[(stage.indexOf(&amp;quot;Won&amp;quot;)&amp;gt;=0)?(&amp;quot;true&amp;quot;):(&amp;quot;false&amp;quot;)]]&amp;gt;&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; Remember to use &lt;code&gt;&amp;lt;![CDATA [...]]&amp;gt;&lt;/code&gt; element for non-problem parsing.)&lt;/p&gt;

&lt;p&gt;Well and this is it! Now you know how to basically use the &lt;code&gt;&amp;lt;transformation&amp;gt;&lt;/code&gt; element. See you next time.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/_klSaA6tb44" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/07/11/transformation-element-usage</feedburner:origLink></entry>
 
 <entry>
   <title>Filtering Embedded Reports &amp; Dashboards via HTTP Parameters</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/jpkj8iAOQSs/filtering-embedded-reports" />
   <updated>2011-06-29T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/29/filtering-embedded-reports</id>
   <content type="html">&lt;h1 id='filtering_embedded_reports__dashboards_via_http_parameters'&gt;Filtering Embedded Reports &amp;#38; Dashboards via HTTP Parameters&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE:&lt;/em&gt; This article previews the functionality that we are going to release in the Release 56 (~ 7/18/2011). Let me know if you are interested in beta testing this functionality. I can invite you to a beta server.&lt;/p&gt;

&lt;p&gt;The embedded reports can be filtered via a their IFrame URL parameters. This blogpost demonstrates the new functionality on a simple example.&lt;/p&gt;

&lt;p&gt;We will start with a simple Salesforce report that shows opportunity amount sliced by the lead source and the opportunity stage.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-1.png' alt='Salesforce Report' /&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s grab the report&amp;#8217;s embedding URL from the embed dialog. We will just cherry-pick the URL from the IFrame &lt;em&gt;src&lt;/em&gt; attribute for now as we&amp;#8217;ll put it directly to the browser.&lt;/p&gt;
&lt;code&gt;https://secure.gooddata.com/reportWidget.html#project=/gdc/projects/Project4&amp;report=/gdc/md/Project4/obj/20887&lt;/code&gt;
&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-2.png' alt='Report URL' /&gt;&lt;/p&gt;

&lt;p&gt;We put the IFrame URL to the browser and the report appears in a separate tab.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-3.png' alt='Embedded Report' /&gt;&lt;/p&gt;

&lt;p&gt;Now we want to filter the report by the &lt;em&gt;StageName&lt;/em&gt; attribute. We need to first determine the unique identifier that we&amp;#8217;ll use for identifying the attribute in the filter. To be precise, we&amp;#8217;ll filter by something what we call label. The labels contain the human readable names. The attributes are technically just unique numbers. Most attributes have just one label. However there might be attributes with multiple labels (e.g. &lt;em&gt;Person&lt;/em&gt; with a &lt;em&gt;Firstname&lt;/em&gt;, &lt;em&gt;Lastname&lt;/em&gt;, and &lt;em&gt;SSN&lt;/em&gt;). The &lt;em&gt;StageName&lt;/em&gt; has two labels and we will filter by the label that contains the stage name.&lt;/p&gt;

&lt;p&gt;First, we need to enumerate all labels associated with the &lt;em&gt;StageName&lt;/em&gt; attribute. Let&amp;#8217;s go to the &lt;em&gt;Manage&lt;/em&gt; section of the GoodData UI, select the &lt;em&gt;Data&lt;/em&gt; tab and find the &lt;em&gt;StageName&lt;/em&gt; attribute.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-4.png' alt='StageName' /&gt;&lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;/gdc/md/Project4/obj/738&lt;/code&gt; suffix of the page&amp;#8217;s URL. This is the GoodData metadata server&amp;#8217;s URL of the &lt;em&gt;StageName&lt;/em&gt; attribute. Every object has its own unique URL. Now we will take a look at the &lt;em&gt;StageName&amp;#8217;s&lt;/em&gt; definition in the gray pages. We&amp;#8217;ll just append the &lt;em&gt;StageName&lt;/em&gt; unique URL to the GoodData server&amp;#8217;s URL &lt;code&gt;https://secure.gooddata.com/gdc/md/Project4/obj/738&lt;/code&gt; and open the result in the browser:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-5.png' alt='StageName Grey Pages' /&gt;&lt;/p&gt;

&lt;p&gt;We can see that the &lt;em&gt;StageName&lt;/em&gt; attribute has two labels (attributeDisplayForms) and that the identifier of the stage name label is &lt;code&gt;label.opportunity.stagename&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yes, I know that we need to display this information on the attribute&amp;#8217;s page to avoid the harakiri above and we&amp;#8217;ll do this ASAP.&lt;/p&gt;

&lt;p&gt;Now once we have the label&amp;#8217;s identifier, we can use it in our report embedding URL. The usage is pretty straightforward:&lt;/p&gt;
&lt;code&gt;https://secure.gooddata.com/reportWidget.html?label.opportunity.stagename=Qualification#project=/gdc/projects/Project4&amp;report=/gdc/md/Project4/obj/20887&lt;/code&gt;
&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-6.png' alt='Filtered Report' /&gt;&lt;/p&gt;

&lt;p&gt;We can also filter by two &lt;em&gt;StageName&lt;/em&gt; values. Please note that &lt;em&gt;Closed Won&lt;/em&gt; value must be URL-encoded because it contains the space.&lt;/p&gt;
&lt;code&gt;https://secure.gooddata.com/reportWidget.html?label.opportunity.stagename=Qualification&amp;label.opportunity.stagename=Closed%20Won#project=/gdc/projects/Project4&amp;report=/gdc/md/Project4/obj/20887&lt;/code&gt;
&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-7.png' alt='Filtered Report' /&gt;&lt;/p&gt;

&lt;p&gt;Multiple conditions with the same label are joined with the &lt;em&gt;OR&lt;/em&gt; logical operator. Multiple conditions with a different labels are &lt;em&gt;ANDed&lt;/em&gt;.&lt;/p&gt;
&lt;code&gt;https://secure.gooddata.com/reportWidget.html?label.opportunity.stagename=Closed%20Won&amp;label.opportunity.leadsource=Partner#project=/gdc/projects/Project4&amp;report=/gdc/md/Project4/obj/20887&lt;/code&gt;
&lt;p&gt;&lt;img src='/images/posts/2011-06-29-filtering-embedded-reports-8.png' alt='Filtered Report' /&gt;&lt;/p&gt;

&lt;p&gt;And least but not last, the same trick works with the embedded dashboards too!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/jpkj8iAOQSs" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/29/filtering-embedded-reports</feedburner:origLink></entry>
 
 <entry>
   <title>Too Many Date Dimensions? Try Events!</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/aoNXi3n690I/events" />
   <updated>2011-06-24T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/24/events</id>
   <content type="html">&lt;h1 id='too_many_date_dimensions_try_events'&gt;Too Many Date Dimensions? Try Events!&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Time can have many different meanings in analytical projects. For example an opportunity can be associated with the time when it was created and the time when a sales guy closed it. I saw quite a few models with way more times associated with a single entity (e.g. helpdesk models). Here is a typical example of a simple sales model that uses &lt;em&gt;created&lt;/em&gt; and &lt;em&gt;closed&lt;/em&gt; date dimensions.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-24-events-original-ldm.png' alt='Sales Data Model' /&gt;&lt;/p&gt;

&lt;p&gt;However end users have sometimes difficult time to figure out why there are two date dimensions and which one they should use in their reports. &amp;#8220;There is only one time&amp;#8221; they think. There is one more problem except the end user usability.&lt;/p&gt;

&lt;p&gt;You can easily create a report &lt;em&gt;Revenue by Time&lt;/em&gt; that is sliced by the &lt;em&gt;Closed Date&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-24-events-revenue-standard.png' alt='Revenue by Time' /&gt;&lt;/p&gt;

&lt;p&gt;You can also create a report &lt;em&gt;Pipeline Generation by Time&lt;/em&gt; that is sliced by the &lt;em&gt;Created Date&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-24-events-pipeline-standard.png' alt='Pipeline by Time' /&gt;&lt;/p&gt;

&lt;p&gt;But as the first report uses the &lt;em&gt;closed&lt;/em&gt; and the second report the &lt;em&gt;created&lt;/em&gt; time dimensions, you can&amp;#8217;t put both metrics to a single chart:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-24-events-pipeline-event.png' alt='Pipeline  Revenue by Time' /&gt;&lt;/p&gt;

&lt;p&gt;You need to model your analytical project differently to achieve the report above. We are getting to something what we call event data models. Here you go:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-24-events-event-ldm.png' alt='Sales Data Model (Event)' /&gt;&lt;/p&gt;

&lt;p&gt;We need to create a special &lt;em&gt;Event&lt;/em&gt; dataset that contains all events related to a specific opportunity. In our case there are two events per each opportunity: &lt;em&gt;created&lt;/em&gt; &amp;#38; &lt;em&gt;closed&lt;/em&gt; . The &lt;em&gt;Event&lt;/em&gt; dataset then has twice as much records as the original &lt;em&gt;Opportunity&lt;/em&gt; dataset. We obviously need to adjust the metrics to not return all amounts multiplied by two. Here are few metrics definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Pipeline [Sum]&lt;/em&gt;: &lt;code&gt;SELECT SUM(Event Amount) WHERE Event Type = created&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Revenue [Sum]&lt;/em&gt;: &lt;code&gt;SELECT SUM(Event Amount) WHERE Event Type = closed AND Status IN (Won)&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Lost Revenue [Sum]&lt;/em&gt;: &lt;code&gt;SELECT SUM(Event Amount) WHERE Event Type = closed AND Status IN (Lost)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics are relatively simple and self describing. The metrics that compute that last opportunity value are a bit more complicated. We need to always find the &amp;#8216;latest&amp;#8217; available event for each opportunity in the &lt;em&gt;Event&lt;/em&gt; dataset. This is why we have the &lt;em&gt;Event ID&lt;/em&gt; FACT in the model. This fact is a unique ID of each event. The later an event occurred, the higher the &lt;em&gt;Event ID&lt;/em&gt; is. So the maximum &lt;em&gt;Event ID&lt;/em&gt; for a specific opportunity identifies the latest event for that opportunity. So we need to first compute this MAX ID.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Last Opportunity Event ID&lt;/em&gt;: &lt;code&gt;SELECT MAX(Event ID) BY Opportunity ID ALL IN ALL OTHER DIMENSIONS&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then the current (latest) opportunity amount, revenue, and pipeline are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Current Amount [Sum]&lt;/em&gt;: &lt;code&gt;SELECT SUM(Event Amount) WHERE Event ID = Last Opportunity Event ID&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Current Revenue [Sum]&lt;/em&gt;: &lt;code&gt;SELECT Current Amount [Sum] WHERE Status = Won&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Current Pipeline [Sum]&lt;/em&gt;: &lt;code&gt;SELECT Current Amount [Sum] WHERE Status = Open&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Current Lost Revenue [Sum]&lt;/em&gt;: &lt;code&gt;SELECT Current Amount [Sum] WHERE Status = Lost&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think about this data model design when you are creating the 6th data dimension in your project. ;-)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/aoNXi3n690I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/24/events</feedburner:origLink></entry>
 
 <entry>
   <title>Using GoodData CL tool - Part 2</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/R5fpJga5TRg/useCases-part2" />
   <updated>2011-06-22T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/22/useCases-part2</id>
   <content type="html">&lt;h1 id='using_gooddata_cl_tool__part_2'&gt;Using GoodData CL tool - Part 2&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href='/blog/2011/06/22/useCases-part1/'&gt;previous part&lt;/a&gt; of this series we&amp;#8217;ve created a new project defined &lt;code&gt;incorrect XML config&lt;/code&gt; file and finally we&amp;#8217;ve updated that file correctly. This is second part of the series in which we&amp;#8217;ll be using basically the same data model and we&amp;#8217;ll update it. Again we have two Examples - first example is about adding new field to the model. In second example we will upload new dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1 - Updating a file (adding new field)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s get down the business. We have actually updated the original &lt;code&gt;data.csv&lt;/code&gt; file and we added Customers &lt;code&gt;FACT&lt;/code&gt; field. So updated &lt;code&gt;CSV file&lt;/code&gt; should looks as follows:&lt;/p&gt;

&lt;p&gt;&amp;#8230;&lt;br /&gt;Date, Revenue, Count, Store, Customers&lt;br /&gt;01/01/2010, 807.84, 816, SFO, 47&lt;br /&gt;&amp;#8230;&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; file has five fields - DATE field, ATTRIBUTE field and three FACT fields )&lt;/p&gt;

&lt;p&gt;What we do next is manually updating the &lt;code&gt;XML config&lt;/code&gt; file adding new column &lt;strong&gt;to the end&lt;/strong&gt; of an XML file. (order is critical!) Here is the updated XML file after adding new column:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;...
...
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;customers&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Customers&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We actually have all parts prepared for updating the data model and for uploading data. We just need the &lt;code&gt;CL script&lt;/code&gt; which has again several parts. It will update data model (&lt;code&gt;GenerateUpdateMaql()&lt;/code&gt; for updating &lt;code&gt;MAQL&lt;/code&gt; file) and load the data:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#1 - CREATE OR RETRIEVE PROJECT ID&lt;/span&gt;
&lt;span class='no'&gt;RetrieveProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - UPDATE DATA MODEL&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateUpdateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#3 - LOAD DATA&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;incremental&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; if you don&amp;#8217;t understand some script commands see our &lt;a href='/gooddata-cl/cli-commands.html'&gt;CL tool documentation&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;After execution we can see the result in GoodData. It wasn&amp;#8217;t so complicated, was it? So review the model and it&amp;#8217;s here with new &lt;code&gt;FACT&lt;/code&gt; field:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/model3.png' alt='Model with customers' /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2 - Adding new dataset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This example is ostensibly more complicated but it won&amp;#8217;t be a big problem at all. So&amp;#8230;let&amp;#8217;s do it! Imagine you need to add new dataset to your model. You have two CSV files containing the data. First is our well known &lt;code&gt;data.csv&lt;/code&gt; as mentioned above with five fields (Date, Revenue, Count, Store, Customers), second is new &lt;code&gt;store.csv&lt;/code&gt; lookup file:&lt;/p&gt;

&lt;p&gt;&amp;#8230; StoreID, Store Name, City, State, Employees SFO, San Francisco Airport Store, San Francisco, CA, 18 &amp;#8230;&lt;/p&gt;

&lt;p&gt;As you can see there are 5 fields. StoreID is the &lt;code&gt;CONNECTION_POINT&lt;/code&gt; that is referenced by Store &lt;code&gt;REFERENCE&lt;/code&gt; in &lt;code&gt;data.csv&lt;/code&gt;, Employees is &lt;code&gt;FACT&lt;/code&gt; field and the rest are &lt;code&gt;ATTRIBUTES&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; remember the functionality of &lt;code&gt;CONNECTION_POINT&lt;/code&gt; and &lt;code&gt;REFERENCE&lt;/code&gt; ldmType. &lt;code&gt;CONNECTION_POINT&lt;/code&gt; has same function as &lt;code&gt;primary key&lt;/code&gt; and &lt;code&gt;REFERENCE&lt;/code&gt; is analogy to &lt;code&gt;foreign key&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;What we do next is generating &lt;code&gt;store.xml&lt;/code&gt; config file for our new lookup file containing the store information. We&amp;#8217;ll do this with &lt;code&gt;CL script&lt;/code&gt; again:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#1 - CREATE OR RETRIEVE PROJECT ID&lt;/span&gt;
&lt;span class='no'&gt;RetrieveProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - GENERATE XML FILES (DATA MODEL) - DO THIS STEP ONLY ONCE!!!&lt;/span&gt;
&lt;span class='no'&gt;GenerateCsvConfig&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvHeaderFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we have to manually check and update the &lt;code&gt;store.xml&lt;/code&gt; file that should looks as follows with StoreID as a &lt;code&gt;CONNECTION_POINT&lt;/code&gt; &lt;code&gt;ldmType&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;schema&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;storeid&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;StoreID&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;CONNECTION_POINT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store_name&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store name&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;city&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;City&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;state&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;State&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;employees&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Employees&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/schema&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Last thing you have to do with &lt;code&gt;XML&lt;/code&gt; files before executing final &lt;code&gt;CL script&lt;/code&gt; is to update &lt;code&gt;Store&lt;/code&gt; column in original &lt;code&gt;schema.xml&lt;/code&gt; file. You should update it as follows adding &lt;code&gt;schemaReference&lt;/code&gt; attribute:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;...
&lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;REFERENCE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;schemaReference&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/schemaReference&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;reference&amp;gt;&lt;/span&gt;storeid&lt;span class='nt'&gt;&amp;lt;/reference&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we have all files prepared to finish this example with the &lt;code&gt;CL script&lt;/code&gt; execution. We&amp;#8217;ll &lt;code&gt;retrieve project id&lt;/code&gt;, then create new data model for &lt;code&gt;store.xml&lt;/code&gt; lookup file, update existing data model for &lt;code&gt;schema.xml&lt;/code&gt; file. Finally we&amp;#8217;ll load data. Remember that you &lt;strong&gt;must load lookup file first&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Here is the script:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#1 - CREATE OR RETRIEVE PROJECT ID&lt;/span&gt;
&lt;span class='no'&gt;RetrieveProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - CREATE DATA MODEL FOR LOOKUP FILE - store.xml&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#3 - UPDATE DATA MODEL FOR EXISTING MODEL - file1.xml&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateUpdateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#4 - LOAD DATA (MUST LOAD LOOKUP FILE FIRST)&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;store.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;incremental&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;incremental&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And&amp;#8230;That&amp;#8217;s it. We&amp;#8217;ve added new dataset to our model. You can review the resulting model in GoodData:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/model4.png' alt='New dataset' /&gt;&lt;/p&gt;

&lt;p&gt;So that&amp;#8217;s all for today. Stay tuned for next blogpost and enjoy coding!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/R5fpJga5TRg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/22/useCases-part2</feedburner:origLink></entry>
 
 <entry>
   <title>Using GoodData CL tool - Part 1</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/50nXvw4tEQU/useCases-part1" />
   <updated>2011-06-22T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/22/useCases-part1</id>
   <content type="html">&lt;h1 id='using_gooddata_cl_tool__part_1'&gt;Using GoodData CL tool - Part 1&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jiri Tobolka&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today we will show you some useful scenarios for our &lt;code&gt;GoodData CL Tool&lt;/code&gt;. This blogpost contains two use cases so you can learn how to correctly upload data file and how to update it later if you&amp;#8217;ve made a mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1 - Uploading file (with incorrect ldm file)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So let&amp;#8217;s start with first, simple but useful use case. You will need to have simple data file (ours has four fields) which we are about to upload to GoodData project (with incorrect ldmField attributes). We have &lt;code&gt;data.csv&lt;/code&gt; data file:&lt;/p&gt;

&lt;p&gt;&amp;#8230;&lt;br /&gt;Date, Revenue, Count, Store&lt;br /&gt;01/01/2010, 807.84, 816, SFO&lt;br /&gt;&amp;#8230;&lt;/p&gt;

&lt;p&gt;It consists of one &lt;code&gt;DATE&lt;/code&gt; field, one &lt;code&gt;ATTRIBUTE&lt;/code&gt; field and two &lt;code&gt;FACT&lt;/code&gt; fields. We&amp;#8217;ll create a project with this simple data file, generate an &lt;code&gt;XML config&lt;/code&gt; file to define a data model and finally upload the data using &lt;code&gt;CL script&lt;/code&gt; tool. The point is creating &lt;code&gt;incorrect XML file&lt;/code&gt; with only one &lt;code&gt;FACT&lt;/code&gt; type and three &lt;code&gt;ATTRIBUTES&lt;/code&gt; which is incorrect.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; You have to &lt;strong&gt;manually edit XML&lt;/strong&gt; file after generating it to define the model schema before you create the data model.)&lt;/p&gt;

&lt;p&gt;You can see the pre-prepared &lt;code&gt;CL script&lt;/code&gt; down here:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#1 - CREATE PROJECT&lt;/span&gt;
&lt;span class='no'&gt;CreateProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;My New Project&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;StoreProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - GENERATE XML FILES (DATA MODEL) - DO THIS STEP ONLY ONCE!!!&lt;/span&gt;
&lt;span class='no'&gt;GenerateCsvConfig&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvHeaderFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After second section you have to &lt;strong&gt;manually edit the XML&lt;/strong&gt; file to define schema. Here is the final XML file:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;...
&lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;date&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Date&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;revenue&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Revenue&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;count&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Count&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; as we define above you edited the schema.xml file incorrectly. It has wrong &lt;code&gt;ldmType&lt;/code&gt; (as mentioned above) and also only two columns have folders assigned to them.)&lt;/p&gt;

&lt;p&gt;Now execute the last two sections to create a data model with data XML config file and CSV data file, and finally load the data:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#1 - CREATE OR RETRIEVE PROJECT&lt;/span&gt;
&lt;span class='no'&gt;RetrieveProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - CREATE DATA MODEL&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file1.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#3 - LOAD DATA&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;incremental&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can now see the resulting model in GoodData:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/model1.png' alt='Wrong model' /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2 - Updating the file and defining fields appropriately (same file as in example 1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In following example we&amp;#8217;ll work with the same file but we&amp;#8217;ll define the &lt;strong&gt;XML config file correctly&lt;/strong&gt;. So what we do.&lt;/p&gt;

&lt;p&gt;Firstly we&amp;#8217;ll edit the &lt;code&gt;XML config file&lt;/code&gt; with setting correct &lt;code&gt;ldmType&lt;/code&gt; (Date as &lt;code&gt;DATE&lt;/code&gt;, Revenue and Count as &lt;code&gt;FACT&lt;/code&gt;, Store as &lt;code&gt;ATTRIBUTE&lt;/code&gt;). Secondly we&amp;#8217;ll add the &lt;code&gt;&amp;lt;folder&amp;gt;&lt;/code&gt; to the XML for all fields that miss this attribute to place field to appropriate folder on front end. Thirdly we&amp;#8217;ll create &lt;code&gt;Date MAQL&lt;/code&gt; files generate the Date dimension and finally we&amp;#8217;ll run the &lt;code&gt;CL script&lt;/code&gt; to update &lt;code&gt;MAQL&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;So after first step you will get the correct XML config file as you can see below:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;...
&lt;span class='nt'&gt;&amp;lt;columns&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;date&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Date&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;DATE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;datetime&amp;gt;&lt;/span&gt;false&lt;span class='nt'&gt;&amp;lt;/datetime&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;format&amp;gt;&lt;/span&gt;MM/dd/yyyy&lt;span class='nt'&gt;&amp;lt;/format&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;schemaReference&amp;gt;&lt;/span&gt;Date&lt;span class='nt'&gt;&amp;lt;/schemaReference&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;revenue&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Revenue&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;count&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Count&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;FACT&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;store&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Store&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;ATTRIBUTE&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
      &lt;span class='nt'&gt;&amp;lt;folder&amp;gt;&lt;/span&gt;Sales&lt;span class='nt'&gt;&amp;lt;/folder&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/columns&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You see that all columns contain &lt;code&gt;&amp;lt;folder&amp;gt;&lt;/code&gt; attributes and all &lt;code&gt;ldmType&lt;/code&gt; fields are correct. We&amp;#8217;ve also added the date &lt;code&gt;schemaReference&lt;/code&gt; to the Date column to connect the dataset to Date dimension. Now we&amp;#8217;ll move to the final step of this example using following GoodData &lt;code&gt;CL script&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;	
&lt;span class='c1'&gt;#1 - CREATE OR RETRIEVE PROJECT ID&lt;/span&gt;
&lt;span class='no'&gt;RetrieveProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;myProject.pid&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#2 - CREATE DATE DIMENSIONS - DO THIS STEP ONLY ONCE!!!&lt;/span&gt;
&lt;span class='no'&gt;UseDateDimension&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Date&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;includeTime&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;date.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;date.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

&lt;span class='c1'&gt;#3 - UPDATE DATA MODEL&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;hasHeader&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;separator&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateUpdateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;#4 - LOAD DATA&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;incremental&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;	
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; Remember the difference between &lt;code&gt;GenerateMaql&lt;/code&gt; and &lt;code&gt;GenerateUpdateMaql&lt;/code&gt;. The first one generates script describing data model from local config file. Second generate alter script that creates the columns available in the local configuration but missing in the remote GoodData project.)&lt;/p&gt;

&lt;p&gt;After executing the whole &lt;code&gt;CL script&lt;/code&gt; you can review the resulting model in GoodData. This is &lt;code&gt;correct model&lt;/code&gt; and should looks as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/model2.png' alt='Correct model with date dimension loaded' /&gt;&lt;/p&gt;

&lt;p&gt;Well this is all for today, in &lt;a href='/blog/2011/06/22/useCases-part2/'&gt;Part 2&lt;/a&gt; we&amp;#8217;ll show you how you can add field to the model and how to add a new dataset. Stay tuned for the next part!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/50nXvw4tEQU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/22/useCases-part1</feedburner:origLink></entry>
 
 <entry>
   <title>Handling User Hierarchies in GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/DYGL5YpYIWo/hierarchies" />
   <updated>2011-06-22T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/22/hierarchies</id>
   <content type="html">&lt;h1 id='handling_user_hierarchies_in_gooddata'&gt;Handling User Hierarchies in GoodData&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tomas has published two nice articles about handling user hierarchies in GoodData. He uses variables for smart implementation of aggregating facts in user hierarchies. Here are the articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://svarovsky-tomas.com/hierarchies.html'&gt;User hierarchies in GoodData&lt;/a&gt; outlines various techniques for implementing user hierarchies&lt;/li&gt;

&lt;li&gt;&lt;a href='http://svarovsky-tomas.com/hierarchies-setup.html'&gt;How to set up a user hierarchy in GoodData&lt;/a&gt; picks one method from the article above and explains the implementation&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/DYGL5YpYIWo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/22/hierarchies</feedburner:origLink></entry>
 
 <entry>
   <title>Modeling Technique - Pushing FACTs Down the Hierarchy</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/yFl_L5nAKwg/shift-fact" />
   <updated>2011-06-21T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/21/shift-fact</id>
   <content type="html">&lt;h1 id='modeling_technique__pushing_facts_down_the_hierarchy'&gt;Modeling Technique - Pushing FACTs Down the Hierarchy&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article shows a special data modeling trick that leads to simpler and more usable data models. This technique is applicable to data models that perform computations on facts in different datasets. Let me demonstrate the technique on a simple data model.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-21-original.ldm.png' alt='Initial Data Model' /&gt;&lt;/p&gt;

&lt;p&gt;We need to combine the &lt;code&gt;Quarterly Bonus&lt;/code&gt; and the &lt;code&gt;Payment&lt;/code&gt; facts in a single report. One option is to follow the &lt;a href='http://developer.gooddata.com/blog/2011/01/21/m-to-n-relationships-in-gooddata/'&gt;M:N modeling technique that we have mentioned earlier&lt;/a&gt;. This technique is suitable for situations when we can&amp;#8217;t change the data model of the project. The option that I&amp;#8217;m introducing in this article require the project&amp;#8217;s data model change. However it leads to more usable metrics and overall better performance. The first step is that we need to push the &lt;code&gt;Employee&lt;/code&gt; dataset&amp;#8217;s facts to the &lt;code&gt;Salary&lt;/code&gt; dataset. Here is the new model:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-21-new.ldm.png' alt='New Data Model' /&gt;&lt;/p&gt;

&lt;p&gt;Let me emphasize that there are 205 employee records and 3876 salary records in my test data. This means that the 205 different &lt;code&gt;Quarterly Bonus&lt;/code&gt; values are somewhat duplicated (de-normalized) in the 3876 salary records. We need to handle the duplicities in our metrics definitions. Here are the metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Salary Paid : &lt;code&gt;SELECT SUM(Payment)&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Employee Quarterly Bonus : &lt;code&gt;SELECT MIN(Bonus (Quarterly)) BY Employee, Quarter/Year (Payment)ALL IN ALL OTHER DIMENSIONS&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Bonus Paid : &lt;code&gt;SELECT SUM(Employee Quarterly Bonus)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MIN aggregation in the &lt;code&gt;Employee Quarterly Bonus&lt;/code&gt; metric converts all duplicate &lt;code&gt;Quarterly Bonus&lt;/code&gt; values to a single value per Employee and Quarter. As all these values should be the same, we could also use the MAX or AVG aggregation.&lt;/p&gt;

&lt;p&gt;Here is the report with all metrics computed on my test data:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-06-21-report.png' alt='Test Report' /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/yFl_L5nAKwg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/21/shift-fact</feedburner:origLink></entry>
 
 <entry>
   <title>New User APIs</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/XujwIgP00IA/domains-and-user-apis" />
   <updated>2011-06-17T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/17/domains-and-user-apis</id>
   <content type="html">&lt;h1 id='new_user_apis'&gt;New User APIs&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href='https://github.com/gooddata/GoodData-CL/downloads'&gt;CL Tool 1.2.30&lt;/a&gt; adds a new &lt;code&gt;CreateUser&lt;/code&gt; command that allows you to programmatically create a new GoodData users. No registration forms, no confirmation e-mails. We can&amp;#8217;t obviously allow an ordinary Joe to start creating thousands of new GoodData users. This is why we came up with the concept of the GoodData domain. GoodData domain is identified by it&amp;#8217;s name (usually a company name of a GoodData partner). It is associated with an authorized GoodData account (username) that can create the new users in the domain. Initially the users can be only created. Later we will allow user modifications, association to a project etc.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll need to request a new domain from GoodData before you can use the new &lt;code&gt;CreateUser&lt;/code&gt; command. &lt;a href='mailto:support@gooddata.com'&gt;Let us know&lt;/a&gt; if you need one. Then you can simply run the command from a CL Tool script:&lt;/p&gt;
&lt;code&gt;CreateUser(domain="...", username="...", password="...", firstName="...", lastName="...", company="...", phone="...", country="...", position="...", ssoProvider="...");&lt;/code&gt;
&lt;p&gt;I think that the most of the command&amp;#8217;s parameters are self-explanatory. Just in case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain - the GoodData users domain. The domain needs to be created by GoodData admins and associated with your GoodData account&lt;/li&gt;

&lt;li&gt;username - the new user&amp;#8217;s username&lt;/li&gt;

&lt;li&gt;password - the new user&amp;#8217;s password&lt;/li&gt;

&lt;li&gt;firstName - the new user&amp;#8217;s first name&lt;/li&gt;

&lt;li&gt;lastName - the new user&amp;#8217;s last name&lt;/li&gt;

&lt;li&gt;company - (optional) the new user&amp;#8217;s company name&lt;/li&gt;

&lt;li&gt;phone - (optional) the new user&amp;#8217;s phone&lt;/li&gt;

&lt;li&gt;country - (optional) the new user&amp;#8217;s country (e.g. &amp;#8216;cz&amp;#8217; or &amp;#8216;us;ca&amp;#8217;)&lt;/li&gt;

&lt;li&gt;position - (optional) the new user&amp;#8217;s position&lt;/li&gt;

&lt;li&gt;ssoProvider - (optional) the new user&amp;#8217;s SSO provider (e.g. SALESFORCE)&lt;/li&gt;

&lt;li&gt;usersFile - (optional) writes the new user&amp;#8217;s URI to the specified file&lt;/li&gt;

&lt;li&gt;append - (optional) should the users file be appended (default is false)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is obviously a nice REST API under the new command. Feel free to dig into the &lt;a href='https://github.com/gooddata/GoodData-CL/blob/master/backend/src/main/java/com/gooddata/integration/rest/GdcRESTApiWrapper.java'&gt;CL tool source code&lt;/a&gt; to figure it out.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/XujwIgP00IA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/17/domains-and-user-apis</feedburner:origLink></entry>
 
 <entry>
   <title>Project Cloning</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/PSR7ZN5VzgM/project-cloning" />
   <updated>2011-06-06T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/06/06/project-cloning</id>
   <content type="html">&lt;h1 id='project_cloning'&gt;Project Cloning&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href='https://github.com/gooddata/GoodData-CL/downloads'&gt;CL Tool 1.2.28&lt;/a&gt; introduced the new project cloning capability. There are two new project export and import commands:&lt;/p&gt;
&lt;code&gt;ExportProject(tokenFile="...", exportUsers="...", exportData="...", authorizedUsers="...")&lt;/code&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;code&gt;ImportProject(tokenFile="...")&lt;/code&gt;
&lt;p&gt;As you can guess the &lt;code&gt;ExportProject&lt;/code&gt; exports the whole content and stores it on a protected storage (you don&amp;#8217;t have direct access to it). The exported project is identified by a token that the command stores in the &lt;code&gt;tokenFile&lt;/code&gt;. You can also define if you wish to export the source project&amp;#8217;s users (&lt;code&gt;exportUsers="true"&lt;/code&gt;) and data (&lt;code&gt;exportData="true"&lt;/code&gt;). The optional &lt;code&gt;authorizedUsers&lt;/code&gt; parameter can specify other GoodData users (comma separated) who will have access to the exported content. The user who is exporting a project has access to it by default.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ImportProject&lt;/code&gt; command imports a previously exported project to a new &lt;em&gt;empty&lt;/em&gt; project. The command needs the &lt;code&gt;tokenFile&lt;/code&gt; file that contains a valid import token generated by the &lt;code&gt;ExportProject&lt;/code&gt; command. The import tokens expire after 48 hours.&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;ExportProject&lt;/code&gt; and &lt;code&gt;ImportProject&lt;/code&gt; work in a project context. You can create, use or open a new project with the &lt;code&gt;CreateProject&lt;/code&gt;, &lt;code&gt;OpenProject&lt;/code&gt;, or &lt;code&gt;UseProject&lt;/code&gt; commands. Here is an example of the complete project cloning script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
# Open an existing project 
OpenProject(id="&amp;lt;your-project-md5-here&amp;gt;");

# Export the project with data and users. Save the import token to importToken.txt file 
ExportProject(tokenFile="importToken.txt", exportUsers="true", exportData="true");

# Create new empty project
CreateProject(name="Clone");

# Import the project metadata, data, and users to the new project.
ImportProject(tokenFile="importToken.txt");
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The logged user must be associated with the &lt;em&gt;admin&lt;/em&gt; role to be able to invoke the API.&lt;/p&gt;

&lt;h2 id='cloning_without_the_cl_tool'&gt;Cloning without the CL Tool&lt;/h2&gt;

&lt;p&gt;If you are not sure in using the CL Tool, you can do the same thing using our so called grey pages. Go to the project maintenance section that is located on the following url:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;project-id&amp;gt;/maintenance&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here you are able to export the project. The system will generate a unique token that you will use lately to import project (store that token somewhere!). You have to create new, empty project and go to the same maintenance grey pages section, but this time choose import. You need to paste that unique token and the exported project will be imported to the new empty project.&lt;/p&gt;

&lt;p&gt;You can choose from same options as you can using the CL Tool.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/PSR7ZN5VzgM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/06/06/project-cloning</feedburner:origLink></entry>
 
 <entry>
   <title>Project Validation</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/CBG6kgFB5c8/project-validation" />
   <updated>2011-05-05T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/05/05/project-validation</id>
   <content type="html">&lt;h1 id='project_validation'&gt;Project Validation&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The project validation API checks a GoodData project for the most common errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Referential integrity issues. For example an employee dataset references some non-existent record in the department dataset.&lt;/li&gt;

&lt;li&gt;Missing attribute values check tries to find an attribute values that are used in report or metric filters and that are no longer present in the data.&lt;/li&gt;

&lt;li&gt;Ambiguous or Transitive references between datasets. Report computation results are unpredictable when a report is computed in project where there are multiple ways how to traverse the project&amp;#8217;s LDM from an attribute A to an attribute B.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project validation API can be invoked at the following URL&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;your-project-id&amp;gt;/validate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The logged user must be associated with the &lt;em&gt;admin&lt;/em&gt; role to be able to invoke the API.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/CBG6kgFB5c8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/05/05/project-validation</feedburner:origLink></entry>
 
 <entry>
   <title>Deleting Data from Project</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/v8kyXlJnlks/deleting-data-from-project" />
   <updated>2011-05-03T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/05/03/deleting-data-from-project</id>
   <content type="html">&lt;h1 id='deleting_data_from_project'&gt;Deleting Data from Project&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by ZD (&lt;a href='http://twitter.com/#!zsvoboda'&gt;@zsvoboda&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The new data deletion API has been introduced in GoodData &lt;a href='http://support.gooddata.com/entries/20068968-release-51-notes-wednesday-may-4-2011'&gt;Release 51&lt;/a&gt;. The API is located at the following URL. &lt;pre&gt;&lt;code&gt;https://secure.gooddata.com/gdc/md/&amp;lt;your-project-id&amp;gt;/dml/manage&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;You can also use the CL tool &lt;code&gt;ExecuteDml(maql="...")&lt;/code&gt; command instead of invoking the API directly.&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;ExecuteDml&lt;/code&gt; and the API require a &lt;em&gt;MAQL DELETE&lt;/em&gt; statement that performs the data deletion. Lets start with a few examples:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM {attr.opportunity.id} WHERE {fact.oppoprtunity.probability}&amp;lt;0 OR {fact.oppoprtunity.amount}&amp;lt;100;
DELETE FROM {attr.opportunity.id} WHERE {created.date.yyyymmdd}&amp;lt;"2009-01-01";
DELETE FROM {attr.opportunity.id} WHERE {created.date.yyyymmdd} BETWEEN "2010-01-01" AND "2010-12-31";
DELETE FROM {attr.opportunity.id} WHERE {label.opportunity.salesrep} IN ("SMITH","CLOONEY");
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the &lt;em&gt;DELETE&lt;/em&gt; syntax is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM &amp;lt;attribute&amp;gt; WHERE &amp;lt;condition&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;#60;attribute&amp;#62;&lt;/strong&gt; - determines the data that will be deleted. If you want to delete whole record from a dataset, use the dataset&amp;#8217;s CONNECTION_POINT attribute.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;&amp;#60;condition&amp;#62;&lt;/strong&gt; - identifies the records that will be deleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets explain the &lt;em&gt;&amp;#60;attribute&amp;#62;&lt;/em&gt; in more detail on an example. The attribute &lt;em&gt;{attr.opportunity.id}&lt;/em&gt; is the CONNECTION_POINT of the &lt;em&gt;Opportunity&lt;/em&gt; dataset. The dataset also contains the &lt;em&gt;{attr.opportunity.status}&lt;/em&gt; attribute. The &lt;em&gt;{attr.opportunity.status}&lt;/em&gt; has the &lt;em&gt;{label.opportunity.status}&lt;/em&gt; label. Then the statement&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM {attr.opportunity.status} WHERE {label.opportunity.status}="Open";
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;deletes the single &lt;em&gt;Open&lt;/em&gt; value from the &lt;em&gt;{attr.opportunity.status}&lt;/em&gt; attribute. The dataset&amp;#8217;s records are preserved. This statement most probably breaks the referential integrity of the project as the records with the &lt;em&gt;Open&lt;/em&gt; status no longer reference any value in the {attr.opportunity.status} attribute.&lt;/p&gt;

&lt;p&gt;The statement&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM {attr.opportunity.id} WHERE {label.opportunity.status}="Open";
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;deletes all records with the attribute {attr.opportunity.status} equal to &lt;em&gt;Open&lt;/em&gt; .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING:&lt;/strong&gt; The &lt;em&gt;MAQL DELETE&lt;/em&gt; command is translated to a corresponding SQL command. This might have certain unwanted side effects. For example, the following statement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM {attr.opportunity.id} WHERE {created.date.yyyymmdd}&amp;gt;"John Doe";
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;deletes all records from the &lt;em&gt;Opportunity&lt;/em&gt; dataset because the value &lt;em&gt;&amp;#8220;John Doe&amp;#8221;&lt;/em&gt; gets converted to a NULL date. Similarly, the statement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DELETE FROM {attr.opportunity.id} WHERE {label.opportunity.salesrep}&amp;gt;"CLOONEY";
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;deletes all opportunities that are associated with sales reps that come after &lt;em&gt;&amp;#8220;CLOONEY&amp;#8221;&lt;/em&gt; in the alphabet.&lt;/p&gt;

&lt;p&gt;And the last one. You need to be the admin to invoke this API.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/v8kyXlJnlks" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/05/03/deleting-data-from-project</feedburner:origLink></entry>
 
 <entry>
   <title>GoodData turned 50 in just 32 months!</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/HtH7sZvglpQ/gooddata-turned-50-in-just-32-months" />
   <updated>2011-04-20T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2011/04/20/gooddata-turned-50-in-just-32-months</id>
   <content type="html">&lt;h1 id='gooddata_turned_50_in_just_32_months'&gt;GoodData turned 50 in just 32 months!&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jaroslav Gergic (&lt;a href='http://twitter.com/#!jgergic'&gt;@jgergic&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We launched &lt;a href='http://support.gooddata.com/entries/20018677-release-50-notes-tuesday-april-12-2011'&gt;Release 50&lt;/a&gt; last week. (Disclaimer: I swear that launching &lt;a href='https://secure.gooddata.com'&gt;GoodData&lt;/a&gt; &lt;em&gt;Release 50&lt;/em&gt; on the 50th anniversary of the first human space flight was a pure coincidence.) Let me recap how we got from &lt;em&gt;Release 1&lt;/em&gt; to &lt;em&gt;Release 50&lt;/em&gt; in such a short period of time.&lt;/p&gt;

&lt;p&gt;The first public beta was launched on July 28 2008 out of a code branch labeled &lt;code&gt;stable-1&lt;/code&gt;. We used to have 4-5 weeks iterations back in 2008 and so we managed to release only 3 additional releases by the end of 2008 bringing the total to 4 releases.&lt;/p&gt;
&lt;div class='imgcenter'&gt;
    &lt;img src='/images/posts/2011-04-20-analyze_small.png' border='0' alt='The first version of report UI' /&gt;
    &lt;label&gt;The first version of report UI&lt;/label&gt;
&lt;/div&gt;
&lt;p&gt;We started 2009 on a 4-week iteration but switched to bi-weekly release trains by mid year. This shorter release cycle allowed us to be much more disciplined about release cut-off and lead to more regular releases, because the pressure to delay the whole release train due to an individual slipping feature was much lower, when our product management knew, that the next release is coming in just two weeks rather than a month.&lt;/p&gt;
&lt;div class='imgcenter'&gt;
    &lt;img src='/images/posts/2011-04-20-report-and-analyze-popupmenu_small.png' border='0' alt='A 2009 report UI' /&gt;
    &lt;label&gt;A 2009 report UI&lt;/label&gt;
&lt;/div&gt;
&lt;p&gt;We created 17 &lt;code&gt;stable-&lt;/code&gt; branches during 2009, but only 15 of them actually reached the production platform. We skipped two releases, because their stabilization took longer than expected, so their features were rather included in the next subsequent release.&lt;/p&gt;

&lt;p&gt;We continued with bi-weekly release and iteration cycle throughout 2010 leading to 23 &lt;code&gt;stable-&lt;/code&gt; release candidates, 19 of them actually reaching the production platform.&lt;/p&gt;

&lt;p&gt;We eventually switched to &lt;em&gt;Kanban&lt;/em&gt; production methodology in Q4 2010, tuned our planning cycle down to one week in order to decrease feature &lt;em&gt;lead time&lt;/em&gt; while keeping bi-weekly release trains in place we have had 6 successful releases to date in 2011.&lt;/p&gt;
&lt;div class='imgcenter'&gt;
    &lt;img src='/images/posts/2011-04-20-sfdc-app_small.png' border='0' alt='Release 50 and the Sales Analytics App' /&gt;
    &lt;label&gt;Release 50 and the Sales Analytics App&lt;/label&gt;
&lt;/div&gt;
&lt;p&gt;We plan to keep increasing the pace of innovation throughout 2011. Stay tuned for even better and faster GoodData!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/HtH7sZvglpQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/04/20/gooddata-turned-50-in-just-32-months</feedburner:origLink></entry>
 
 <entry>
   <title>Server side Charting - a case for Node.js and Erlang</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/-clMxBzTey0/charting-export-using-nodejs-and-erlang" />
   <updated>2011-02-22T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/02/22/charting-export-using-nodejs-and-erlang</id>
   <content type="html">&lt;h1 id='server_side_charting__a_case_for_nodejs_and_erlang'&gt;Server side Charting - a case for Node.js and Erlang&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;by Jan Pradac (&lt;a href='http://twitter.com/#!prajanq'&gt;@prajanq&lt;/a&gt;) &amp;#38; Standa Opichal (&lt;a href='http://twitter.com/#!opichals'&gt;@opichals&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;GoodData &lt;a href='http://support.gooddata.com/entries/424738-release-46-notes-february-2-2011'&gt;Release 46&lt;/a&gt; sports a long awaited chart export capability. In this post, we won&amp;#39;t focus on the feature itself, but rather on the interesting stuff going on under the hood. Since this is a completely new piece of functionality in our platform, we chose it to be a testing ground for the new infrastructure we are experimenting with.&lt;/p&gt;

&lt;h1 id='gooddata_charting_engine'&gt;GoodData Charting Engine&lt;/h1&gt;

&lt;p&gt;Let’s start from the beginning. Two years ago we were facing the need to implement a client-side charting capability. We started by exploring what was available at the time and subsequently chose a 3rd party commercial library. However, it soon turned out that the 3rd party library wasn&amp;#39;t able to meet our longer term requirements so we decided to dedicate resources to develop a charting library in-house. Because of demands for high user interactivity we developed a native JS charting library. We anticipated the exporting feature would be needed later so we were thinking about either maintaining parallel code base on the server side, or maybe running our client JS library under &lt;a href='http://www.mozilla.org/rhino/'&gt;Rhino&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As new features and chart types kept piling up and our charting library became more complex, it became obvious that the possibility to maintain a feature-identical server-side code base was no longer an option. When the chart exporting feature appeared on our short term roadmap, we started exploring options on how to deploy our JS charting library on the server side. The first idea on how to deal with this was the &lt;a href='https://github.com/davglass/nodejs-yui3'&gt;nodejs-yui3&lt;/a&gt; project by YUI developer Dave Glass. Nodejs-yui3 enables execution of &lt;a href='http://developer.yahoo.com/yui/3/'&gt;YUI3&lt;/a&gt; which we use as our primary JavaScript framework under &lt;a href='http://nodejs.org/'&gt;Node.js&lt;/a&gt;. We started experimenting with this in February 2010. After a while Dave&amp;#39;s endeavor got public mainly via his great post &lt;a href='http://www.yuiblog.com/blog/2010/04/05/running-yui-3-server-side-with-node-js/'&gt;&amp;#39;Running YUI 3 Server-Side with Node.js&amp;#39;&lt;/a&gt;. The second trigger was David Padbury&amp;#39;s blog post &lt;a href='http://blog.davidpadbury.com/2010/10/03/using-nodejs-to-render-js-charts-on-server/'&gt;&amp;#39;Using NodeJs to render JavaScript charts on the server&amp;#39;&lt;/a&gt;. After considering our options, we decided to go ahead and use this technology in production.&lt;/p&gt;

&lt;h1 id='serverside_charting_execution_chain'&gt;Server-side Charting Execution Chain&lt;/h1&gt;

&lt;p&gt;Exporting charts is generally a multi-step process. First, the data needs to be pulled from the data warehouse. The next step, is rendering the data into a vector graphics representation, the step which is performed by our JS charting library. The last step, involves converting the vectorised graphics into another output format like PDF or PNG. In general this process is what is usually called a multi-part long-running operation - a workflow.&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/2011-02-22-export-service-rest.png' alt='Export Service Chain' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;h1 id='meet_taskman__the_asynchronous_task_management_middleware'&gt;Meet TaskMan - the asynchronous task management middle-ware&lt;/h1&gt;

&lt;p&gt;Some sort of an orchestrator - an oversight entity - taking care of scheduling, monitoring and error handling of all stages of the process is necessary. Erlang with its OTP platform and the inherent supervisor concept seemed to be an ideal choice for this portion of the middleware. Since we already built some prototypes of what we call TaskMan (a task manager) in Erlang earlier, we decided the server side charting feature would be an ideal candidate to battle test Erlang in GoodData in production deployment. The TaskMan is a distributed long-running operation scheduler/manager with REST API. It employs Erlang’s integrated distributed transaction DBMS - &lt;a href='http://www.erlang.org/doc/man/mnesia.html'&gt;Mnesia&lt;/a&gt; which allows us to brace for multi-node deployments and &lt;a href='http://yaws.hyber.org/'&gt;Yaws&lt;/a&gt; a high performance web server for fast REST API tasks management. The initial TaskMan design was intentionally kept minimal. It receives a task definition and manages a pool of workers to process it.&lt;/p&gt;

&lt;h1 id='execution_workflow_implementation'&gt;Execution Workflow Implementation&lt;/h1&gt;
&lt;p&gt;
&lt;center&gt;&lt;img src='/images/posts/2011-02-22-export-service.png' alt='Export Service Architecture' /&gt;&lt;/center&gt;
&lt;/p&gt;
&lt;p&gt;There are workers configured for each of the steps of the chart export process. The first worker manages the data retrieval. It uses our standard REST APIs and fetches all the data necessary for a particular chart export job.&lt;/p&gt;

&lt;p&gt;The second worker is for the actual chart rendering, a process analogous to what is happening in the web browser when rendering a chart on the client. Using YUI on both sides allowed us to share the browser built code on the server side in Node.js with suprisingly, almost no additional work.&lt;/p&gt;

&lt;p&gt;The final step is the conversion of the rendered SVG to a PDF document or PNG image file. We built a worker based on the good old Apache Batik Rasterizer using Apache FOP (for generating PDF). The only extra step was adjusting the SVG markup to avoid generic SVG-&amp;gt;PDF conversion transparency issues.&lt;/p&gt;

&lt;h1 id='conclusion'&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;We have been very pleased by the result and are getting the exact same chart rendering using the browser as well as in the exported documents. We are looking forward to exploiting the opportunities this great piece of infrastructure provides. The idea of sharing the JavaScript code beyond just the browser environment is very powerful. Using the Erlang-built TaskMan enables us to distribute the worker load with minimal effort.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/-clMxBzTey0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/02/22/charting-export-using-nodejs-and-erlang</feedburner:origLink></entry>
 
 <entry>
   <title>Modeling Many-to-Many relationships in GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/05uw6WESCO4/m-to-n-relationships-in-gooddata" />
   <updated>2011-01-21T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/01/21/m-to-n-relationships-in-gooddata</id>
   <content type="html">&lt;h1 id='modeling_manytomany_relationships_in_gooddata'&gt;Modeling Many-to-Many relationships in GoodData&lt;/h1&gt;

&lt;p&gt;When using GoodData, constructing a good data model is cruicial to the healthy functioning of your project. How you create your model directly influences the way you construct your reports and metrics - particularly how GoodData aggregates your data (and assumes aggregations). Typical 1:N relationships are fairly easy - represented as oriented edges in your model graph - each &lt;code&gt;Year&lt;/code&gt; has multiple &lt;code&gt;Months&lt;/code&gt;, each &lt;code&gt;Month&lt;/code&gt; has multiple &lt;code&gt;Days&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-ymd-ldm.png' alt='Date Dimension Model Example' /&gt;&lt;/p&gt;

&lt;p&gt;However sometimes you need to try to model M:N relationships. A typical usecase like this is tagging. There are typically multiple tags associated with one object and multiple objects tagged with one specific tag.&lt;/p&gt;

&lt;h2 id='the_data_model'&gt;The Data Model&lt;/h2&gt;

&lt;p&gt;To take a specific example, let&amp;#8217;s take support tickets - the &lt;code&gt;Ticket&lt;/code&gt; and &lt;code&gt;Tag&lt;/code&gt; attributes. As in relational databases, in order to create 1:N relationships, a third, joining attribute &lt;code&gt;TicketTag&lt;/code&gt; must be introduced. This attribute contains unique &lt;code&gt;Ticket&lt;/code&gt;-&lt;code&gt;Tag&lt;/code&gt; pairs (ie. if ticket X is tagged with tag Y, there is an XY entry in this ticket). For each entry in this attribute, there is a 1:N relationship with tickets (each one &lt;code&gt;Ticket&lt;/code&gt; can have multiple &lt;code&gt;TicketTag&lt;/code&gt; pairs, but each pair corresponds to only one ticket) and 1:M relantionship with tags.&lt;/p&gt;

&lt;p&gt;Let us now assume that each ticket has some facts associated with it - for example &lt;code&gt;ResolutionTime&lt;/code&gt; (the number of hours it took to close it) - and we would like to display a report showing the total resolution time of tickets marked with a certain tag. Additionally, for implementation reasons, let&amp;#8217;s also create a &lt;code&gt;Dummy&lt;/code&gt; fact associated with this &lt;code&gt;TicketTag&lt;/code&gt; attribute. It can really be just a column of values &amp;#8220;1&amp;#8221; or anything.&lt;/p&gt;

&lt;p&gt;Thus, our data model now looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-ldm.png' alt='Data Model' /&gt;&lt;/p&gt;

&lt;h2 id='naive_approach'&gt;Naive Approach&lt;/h2&gt;

&lt;p&gt;Using a straightforward approach would be to define a metric AVG(ResolutionTime) and then create a report with that metric and Tags. But this is what happens:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-tags-disabled.png' alt='Tags Attribute Disabled' /&gt;&lt;/p&gt;

&lt;p&gt;As you can see the &lt;code&gt;Tags&lt;/code&gt; attribute is disabled. This happens because GoodData does not know how to split the &lt;code&gt;ResolutionTime&lt;/code&gt; by &lt;code&gt;Tag&lt;/code&gt; - if a ticket has tags (red,hot,chili) and a resolution time of 10 hours - how do the hours divide between the 3 tags?&lt;/p&gt;

&lt;h2 id='enforce_aggregation'&gt;Enforce Aggregation&lt;/h2&gt;

&lt;p&gt;Fortunatelly, there is a way in advanced MAQL to override this default behavior via enforced aggregation rules. First, let&amp;#8217;s modify our metric like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;SELECT&lt;/span&gt; &lt;span class='k'&gt;AVG&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;ResolutionTime&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;BY&lt;/span&gt; &lt;span class='nv'&gt;Ticket&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;ALL IN ALL OTHER DIMENSIONS&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;BY&lt;/code&gt; section now specifies that the metric should be aggregated on a per-ticket level and should ignore any attributes from other dimensions when being computed. Now it is already possible to add the &lt;code&gt;Tag&lt;/code&gt; to the report, but still the result is still not what we intended:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-tags-identical.png' alt='Tags Metric Identical' /&gt;&lt;/p&gt;

&lt;p&gt;The metric behaves exactly as - it aggregates &lt;code&gt;ResolutionTime&lt;/code&gt; for each &lt;code&gt;Ticket&lt;/code&gt;, but as tickets are not directly connected to tags, it ignores any attributes from other dimensions (&lt;code&gt;ALL IN ALL OTHER&lt;/code&gt;) - and produces a average of &lt;strong&gt;all data&lt;/strong&gt; in your warehouse.&lt;/p&gt;

&lt;h2 id='wrap_in_a_different_aggregation'&gt;Wrap In a Different Aggregation&lt;/h2&gt;

&lt;p&gt;If we were to add Tickets to the report above, we would see each ticket containing all tags - since for each ticket-tag combination, the metric just computes value over the whole warehouse. Now comes &lt;strong&gt;the trick&lt;/strong&gt; - use this as a sub-metric and add a fact at the TicketTags level (and multiplying it by 0 we eliminate it from influencing the result):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;SELECT AVG&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
	&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;SELECT SUM&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;ResolutionTime&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;BY&lt;/span&gt; &lt;span class='nv'&gt;Ticket&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;ALL IN ALL OTHER DIMENSIONS&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
	&lt;span class='o'&gt;+&lt;/span&gt;
	&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='nv'&gt;Dummy&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it&amp;#8217;s useful to view the resulting report split by both Tickets and Tags:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-tickettags.png' alt='Metric Split By Ticket and Tags' /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the metric is still identical for all tags in one specific ticket (since the internal metric is aggregated by &lt;code&gt;Ticket&lt;/code&gt;). However only pairs of tickets-tags that actually have a &lt;code&gt;Dummy&lt;/code&gt; fact associated with them are listed. Removing the &lt;code&gt;Ticket&lt;/code&gt; attribute from the report now finally results in our intended report:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-21-m-to-n-modeling-final.png' alt='Final Report' /&gt;&lt;/p&gt;

&lt;h2 id='summary'&gt;Summary&lt;/h2&gt;

&lt;p&gt;In retrospect, let&amp;#8217;s have a look how we achieved M:N modeling in GoodData:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;we split the Ticket-Tag M:N relationship into two 1:N and 1:M relationships using a &amp;#8220;joining&amp;#8221; &lt;code&gt;TicketTag&lt;/code&gt; attribute and included a &amp;#8220;dummy&amp;#8221; fact with this attribute&lt;/li&gt;

&lt;li&gt;we defined an &amp;#8220;inner&amp;#8221; metric with enforced aggregation by the &lt;code&gt;Ticket&lt;/code&gt; (and by &lt;code&gt;ALL IN ALL OTHER DIMENSIONS&lt;/code&gt;)&lt;/li&gt;

&lt;li&gt;we wrapped the inner metric in an outter metric, used the &lt;code&gt;Dummy&lt;/code&gt; fact to filter out just the ticket-tag pairs that exist and &amp;#8220;repositioned&amp;#8221; the aggregation to TicketTag level&lt;/li&gt;

&lt;li&gt;we constructed the final report sliced by &lt;code&gt;Tag&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can read more on this topic in our documentation on &lt;a href='/docs/maql.html'&gt;MAQL metrics&lt;/a&gt;. Examples of setting up hierarchies using GoodData CL can be found in the &lt;a href='/gooddata-cl/examples/hr/'&gt;HR example&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/05uw6WESCO4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/01/21/m-to-n-relationships-in-gooddata</feedburner:origLink></entry>
 
 <entry>
   <title>Adding Hyperlinks to Your Attributes</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/TU9p88zjq_g/adding-hyperlinks-to-attribute" />
   <updated>2011-01-13T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/01/13/adding-hyperlinks-to-attribute</id>
   <content type="html">&lt;h1 id='adding_hyperlinks_to_your_attributes'&gt;Adding Hyperlinks to Your Attributes&lt;/h1&gt;

&lt;p&gt;When analyzing data from online applications (Salesforce, Zendesk, etc.), it makes a lot of sense to set up some attributes to be clickable hyperlinks leading back to the original data. Take this &lt;em&gt;example&lt;/em&gt; of Susan&amp;#8217;s open support tickets in Zendesk, along with the age of the tickets:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-13-open-tickets.png' alt='Open Tickets' /&gt;&lt;/p&gt;

&lt;p&gt;Wouldn&amp;#8217;t it be nice if you could click on the ID of the individual support ticket and open it directly back in the original application? Well let&amp;#8217;s have a look at how we can get this done.&lt;/p&gt;

&lt;p&gt;First, we&amp;#8217;ll need to extend our original data with a new column &lt;code&gt;URL&lt;/code&gt; containing the link for each ticket:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Ticket ID, Asignee, URL, ...
...
764613,Abbott Susan B., http://yourcompany.zendesk.com/tickets/764613
765427,Abbott Susan B., http://yourcompany.zendesk.com/tickets/765427
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we need to edit our XML schema to add information about the new column. We will set this up as a &lt;code&gt;LABEL&lt;/code&gt; ldmType, adding it as another view to our original attribute that should have the hyperlink (in this case Ticket ID). Note the &lt;code&gt;&amp;lt;reference&amp;gt;&lt;/code&gt; field containing the &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; of the attribute:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;...
&lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;url&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;URL&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;LABEL&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;reference&amp;gt;&lt;/span&gt;ticketid&lt;span class='nt'&gt;&amp;lt;/reference&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next, we&amp;#8217;ll need to modify the data model in our project. The easiest way to do this is by using the &lt;code&gt;GenerateUpdateMaql&lt;/code&gt; command, which analyzes changes to your XML schema (compared to the current status in your project) and produces an &amp;#8220;update MAQL&amp;#8221; that will modify your model accordingly:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;OpenProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;project-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateUpdateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;update.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can review the &lt;code&gt;update.maql&lt;/code&gt; file at this point. Before you run it in your project however, we need to add one extra line specifying the newly created LABEL as a &lt;em&gt;hyperlink&lt;/em&gt;. You can insert it just above the &lt;code&gt;SYNCHRONIZE&lt;/code&gt; line at the end:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='maql'&gt;&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='n'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.dataset.ticketid}&lt;/span&gt; &lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='n'&gt;LABELS&lt;/span&gt; &lt;span class='nv'&gt;{label.dataset.ticketid.url}&lt;/span&gt; &lt;span class='n'&gt;HYPERLINK&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; the MAQL identifiers &lt;code&gt;{attr.dataset.ticketid}&lt;/code&gt; and &lt;code&gt;{label.dataset.ticketid.url}&lt;/code&gt; will need to be replaced by your own identifiers, to be found in the same update MAQL file.)&lt;/p&gt;

&lt;p&gt;All that remains is to run this modified MAQL script in your project and upload the new data including hyperlink labels:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;OpenProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;project-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;header&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;update.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The same report as before now shows hyperlinks on each ticket ID that can be clicked to open a new window with the original ticket in Zendesk.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-13-open-tickets-hyperlinked.png' alt='Hyperlinked Open Tickets' /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Note&lt;/strong&gt;: If the window doesn&amp;#8217;t open for you, your browser is probably blocking pop-up windows and you might need to allow &lt;code&gt;secure.gooddata.com&lt;/code&gt; to open popups.)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/TU9p88zjq_g" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/01/13/adding-hyperlinks-to-attribute</feedburner:origLink></entry>
 
 <entry>
   <title>Defining Custom Sorting Order For An Attribute</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/Eb2le7J7ZnM/custom-sorting-order" />
   <updated>2011-01-10T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2011/01/10/custom-sorting-order</id>
   <content type="html">&lt;h1 id='defining_custom_sorting_order_for_an_attribute'&gt;Defining Custom Sorting Order For An Attribute&lt;/h1&gt;

&lt;p&gt;I am often asked how to define a custom sort order in GoodData. Today I&amp;#8217;ll show you how to setup custom sorting for an attribute using MAQL DDL and an additional sorting data column.&lt;/p&gt;

&lt;p&gt;Alphabetical or numeric ordering isn&amp;#8217;t always the most appropriate way to sort data. This occurs especially in situations where data has some custom, inherent order that people understand. One example could be customer stages in a CRM system or ticket status in a support/bug tracking system:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1. New
2. Open
3. Pending
4. Closed&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These items have an inherent, obvious order which is not alphabetical. Let&amp;#8217;s take a simplified dataset in the form of this &lt;code&gt;data.csv&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Status,Age
New,140
Open,182
Pending,198
Closed,270&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can imagine yourself what the &lt;a href='/gooddata-cl/xml-config.html'&gt;schema XML file&lt;/a&gt; looks like (&lt;code&gt;Status&lt;/code&gt; is an attribute, &lt;code&gt;Age&lt;/code&gt; is a fact). By default GoodData is going to create a report like this:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-10-report-wrong-sorting.png' alt='Report With Wrong Sorting' /&gt;&lt;/p&gt;

&lt;p&gt;The intuitive way to sort this is to start dragging rows around in the report to sort the data Excel-style. However this isn&amp;#8217;t a good idea in an analytical system - data can change, new statuses can emerge etc. Instead, the appropriate place to solve this sorting issue is in the data layer. We&amp;#8217;re going to use another column in our dataset called &lt;code&gt;Status Ordering&lt;/code&gt;. Let&amp;#8217;s change the &lt;code&gt;data.csv&lt;/code&gt; to look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Status,Status Ordering,Age
New,1,140
Open,2,182
Pending,3,198
Closed,4,270&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Correspondingly, we need to add one more column definition to the &lt;code&gt;schema.xml&lt;/code&gt; file, setting up the &lt;code&gt;Status Ordering&lt;/code&gt; column as a &lt;code&gt;LABEL&lt;/code&gt; to the &lt;code&gt;Status&lt;/code&gt; attribute:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='xml'&gt;&lt;span class='nt'&gt;&amp;lt;column&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;name&amp;gt;&lt;/span&gt;statussort&lt;span class='nt'&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Status Sort&lt;span class='nt'&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;ldmType&amp;gt;&lt;/span&gt;LABEL&lt;span class='nt'&gt;&amp;lt;/ldmType&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;dataType&amp;gt;&lt;/span&gt;INT&lt;span class='nt'&gt;&amp;lt;/dataType&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;reference&amp;gt;&lt;/span&gt;status&lt;span class='nt'&gt;&amp;lt;/reference&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/column&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To set up sorting correctly you need to specify INT datatype for the label. If you don&amp;#8217;t do that sorting will be based on alphabetic principles. (12 comes before 2 and so on&amp;#8230;)&lt;/p&gt;

&lt;p&gt;As always, when modifying the schema XML, we now need to project these changes into our project. We can create a new project from scratch, but sometimes that&amp;#8217;s not practical. Or we can use the little known &lt;a href='http://developer.gooddata.com/gooddata-cl/cli-commands.html#logical_model_management_commands'&gt;&lt;code&gt;GenerateUpdateMaql&lt;/code&gt; command&lt;/a&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;OpenProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;project-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;GenerateUpdateMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;update.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This generates the &lt;code&gt;update.maql&lt;/code&gt; file describing the changes to your data model that add the new &lt;code&gt;LABEL&lt;/code&gt; column. Before following through with applying the changes to the project and loading the new data, we will make one more change specifying the new &lt;code&gt;LABEL&lt;/code&gt; column as a sorting column for the &lt;code&gt;Status&lt;/code&gt; attribute. You can add it at the end of the file just &lt;strong&gt;above&lt;/strong&gt; the &lt;code&gt;SYNCHRONIZE&lt;/code&gt; command: (Note that the specific MAQL identifiers can be different for your model - you can find them by inspecting the generated &lt;code&gt;update.maql&lt;/code&gt;)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='maql'&gt;&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.dataset.status}&lt;/span&gt; &lt;span class='k'&gt;ORDER BY&lt;/span&gt; &lt;span class='nv'&gt;{label.dataset.status.statussort}&lt;/span&gt; &lt;span class='k'&gt;ASC&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Save the file and run the following script to make the model changes and load the new data:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;OpenProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;project-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;UseCsv&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;csvDataFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;data.csv&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;configFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;schema.xml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;update.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='no'&gt;TransferData&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now our &lt;code&gt;Status&lt;/code&gt; attribute sorts naturally as expected with GoodData sorting all rows behind the scenes according to the Status Sorting column in your source data:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/2011-01-10-report-correct-sorting.png' alt='Report With Correct Sorting' /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/Eb2le7J7ZnM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2011/01/10/custom-sorting-order</feedburner:origLink></entry>
 
 <entry>
   <title>Major release - GoodData CL v1.2 - Migration &amp; New Features</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/R6tbbgpPArg/migration-to-gooddata-cl-1.2" />
   <updated>2010-12-10T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2010/12/10/migration-to-gooddata-cl-1.2</id>
   <content type="html">&lt;h1 id='new_gooddata_cl_version_12_is_here'&gt;New GoodData CL Version 1.2 Is Here&lt;/h1&gt;

&lt;p&gt;Starting today, when you download the latest version of GoodData CL, you will get the new v1.2. It has been in preparation for weeks. Here is a run-down of new features and important migration information for existing projects:&lt;/p&gt;

&lt;h2 id='new_features'&gt;New Features:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;much&lt;/em&gt; faster in loading data into your projects&lt;/li&gt;

&lt;li&gt;does not use local MySQL/Derby database anymore (details in &lt;a href='/blog/2010/10/15/data-upload-apis'&gt;previous post&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;this version also supports multiple profiles when loading into &lt;a href='/blog/2010/10/26/google-analytics-multiple-profiles/'&gt;Google Analytics&lt;/a&gt; and has a separate tool for pushing &lt;a href='/blog/2010/11/02/automated-notifications-messages/'&gt;notification streams&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;you can export all your metrics/reports/dashboards, back them up, and load them into another project (allowing you to clone projects, migrate your dashboards to a new project etc.)&lt;/li&gt;

&lt;li&gt;you can now use the built-in date dimension with time data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='migration_of_older_projects'&gt;Migration of Older Projects:&lt;/h2&gt;

&lt;p&gt;Your projects can either be used &lt;strong&gt;exclusively either with CL 1.1 or with CL 1.2&lt;/strong&gt;. Existing projects created with CL tool 1.1 and lower will &lt;strong&gt;need to be migrated&lt;/strong&gt; to be used with CL 1.2. It is important you understand the changes. CL 1.1 used a local database (Derby or MySQL) to store lookup tables of IDs for your attribute string values. When new data was loaded (both incremental and full-replace) identical IDs are assigned to the same attribute values so that filters defined in your reports keep working.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The local database has been removed in 1.2 and is now kept on GoodData servers. If you have a v1.1 project, you will need to run the &lt;code&gt;MigrateDatasets&lt;/code&gt; command. This command will transfer your local lookup tables to GoodData servers and sets up the project for CL v1.2. After this change, the project should not be used with CL 1.1 anymore. The command looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gdi.sh -u ... -p ... -e &amp;#39;MigrateDatasets(configFiles=&amp;quot;list-of-files&amp;quot;);&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;list-of-files&lt;/code&gt; is a comma-separates list of paths to XML schema files that represent datasets that are to be migrated.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Additionally, you&amp;#8217;ll need to modify your project model to adhere to the way the new version constructs data models. Only projects that contain datasets without any facts require this migration. If you try to load data into such a project, you’ll most probably receive an error reading “Unknown import mode” or complaints about missing &lt;code&gt;factsof&lt;/code&gt; attribute. If your project requires migration, you’ll need to execute a migration MAQL script via the &lt;code&gt;ExecuteMaql&lt;/code&gt; command. The migration script deletes the ambiguous &lt;code&gt;factsof&lt;/code&gt; attribute that has been created for the dataset’s &lt;code&gt;CONNECTION_POINT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll need to run the &lt;code&gt;ALTER ATTRIBUTE&lt;/code&gt; statement on the line 5 for every &lt;code&gt;REFERENCE&lt;/code&gt; to the migrated dataset. You&amp;#8217;ll also need to &lt;code&gt;SYNCHRONIZE&lt;/code&gt; all &lt;code&gt;REFERENCE&lt;/code&gt; datasets.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.&amp;lt;connection-point-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{f_&amp;lt;dataset-name&amp;gt;.id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;DATASET&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;dataset-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;# You need to add this statement for each REFERENCE to the migrated dataset&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.&amp;lt;connection-point-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;ADD&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt;
    &lt;span class='nv'&gt;{d_&amp;lt;reference-dataset-name&amp;gt;_&amp;lt;reference-name&amp;gt;.&amp;lt;dataset-name&amp;gt;_id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;dataset-name&amp;gt;}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Also you need to synchronize all REFERENCE datasets&lt;/span&gt;
&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;reference-dataset-name&amp;gt;}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more details and further examples, see this &lt;a href='/blog/2010/10/25/gooddata-cl-migration'&gt;older blog post&lt;/a&gt; about the issue.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id='cl_commands_changes'&gt;CL Commands Changes&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;New Commands:&lt;/strong&gt; &lt;code&gt;MigrateDatasets&lt;/code&gt;, &lt;code&gt;RetrieveAllObjects&lt;/code&gt;, &lt;code&gt;StoreAllObjects&lt;/code&gt; (see &lt;a href='/gooddata-cl/cli-commands.html#metadata_management_commands'&gt;Metadata Management Commands&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changed Commands:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UseDateDimension&lt;/code&gt; now supports time (&lt;code&gt;includeTime = &amp;lt;true | false&amp;gt;&lt;/code&gt;), you need to use the &lt;code&gt;&amp;lt;datetime&amp;gt;true&amp;lt;/datetime&amp;gt;&lt;/code&gt; element in your XML config to activate this and you must use &lt;code&gt;TransferData&lt;/code&gt; command to load the time portion of the date dimension - see the XML and cmd files of &lt;a href='https://github.com/gooddata/GoodData-CL/tree/master/cli-distro/examples/forex'&gt;Forex example&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;support for the &lt;code&gt;&amp;lt;dataType&amp;gt;&lt;/code&gt; key directly in your &lt;a href='/gooddata-cl/xml-config.html'&gt;XML schema&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;new &lt;code&gt;IDENTITY&lt;/code&gt; datatype creates a new column with a unique ID for each row of your dataset. It creates the ID as an MD5 hash of the whole row.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;DATE&lt;/code&gt; format supports time, &lt;a href='/gooddata-cl/xml-config.html'&gt;see more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Renamed Commands:&lt;/strong&gt; We&amp;#8217;ve simplified/consolidated names of the CL tool commands. Old names are still working, however they will be deprecated in the future:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Load*&lt;/code&gt; -&amp;gt; &lt;code&gt;Use*&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;DropProject&lt;/code&gt; -&amp;gt; &lt;code&gt;DeleteProject&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;StoreProject&lt;/code&gt; -&amp;gt; &lt;code&gt;RememberProject&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;RetrieveProject&lt;/code&gt; -&amp;gt; &lt;code&gt;UseProject&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Discontinued commands:&lt;/strong&gt; &lt;code&gt;DropIntegrationDatabase&lt;/code&gt;, &lt;code&gt;DropSnapshots&lt;/code&gt;, &lt;code&gt;Transfer*Snapshot&lt;/code&gt; (use TransferData instead)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/R6tbbgpPArg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/12/10/migration-to-gooddata-cl-1.2</feedburner:origLink></entry>
 
 <entry>
   <title>Three reasons why you should join Cloudstock hackathon and use GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/mVgbTBX8TNw/three-reasons-why-to-join-hackathon-with-gooddata" />
   <updated>2010-12-06T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2010/12/06/three-reasons-why-to-join-hackathon-with-gooddata</id>
   <content type="html">&lt;h1 id='three_reasons_why_you_should_join_cloudstock_hackathon_and_use_gooddata'&gt;Three reasons why you should join Cloudstock hackathon and use GoodData&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You need to work with at least two Cloudstock partners, and GoodData already has connectors to Salesforce and Google Analytics. We can show you a demo mashup with Twilio. We are running on Amazon Web Services. It just cannot be easier.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;ReadWriteWeb wants to see the best data vizualization. I believe it&amp;#8217;s not about the most fancy chart, it&amp;#8217;s about a great idea what to visualize. Once you have the idea, coding it in GoodData will be a pleasure. You just need to be prepared for the fame.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;You can win the latest iPod Touch 32 GB. We are sponsoring the Best Analytic Innovation award. Think out of the box–you&amp;#8217;re developer, after all.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our top developers are here to help you. Feel free to ask us! We will not code your app but we help you keep moving.&lt;/p&gt;

&lt;p&gt;If you decide to be a hackathoner, &lt;a href='http://twitter.com/gooddata_dev'&gt;follow us on Twitter&lt;/a&gt; and don&amp;#8217;t forget to &lt;a href='http://www.developerforce.com/events/hackathon/registration.php'&gt;register your team by 1:15pm&lt;/a&gt;!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/mVgbTBX8TNw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/12/06/three-reasons-why-to-join-hackathon-with-gooddata</feedburner:origLink></entry>
 
 <entry>
   <title>CloudStock Session Slides</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/45gF48vxDXU/slides-from-cloudstock-sessions" />
   <updated>2010-12-02T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2010/12/02/slides-from-cloudstock-sessions</id>
   <content type="html">&lt;h1 id='cloudstock_session_slides'&gt;CloudStock Session Slides&lt;/h1&gt;

&lt;h3 id='one_stop_shop_for_analytics_gooddata_apis_and_developer_tools'&gt;One Stop Shop for Analytics: GoodData APIs and Developer Tools&lt;/h3&gt;

&lt;p&gt;Jakub Nešetřil has presented a high-level overview of GoodData developer tools and APIs.&lt;/p&gt;
&lt;div id='__ss_6054703' style='width:425px'&gt;&lt;strong style='display:block;margin:12px 0 4px'&gt;&lt;a href='http://www.slideshare.net/jakub.nesetril/one-stopshopforanalytics' title='GoodData: One Stop Shop for Analytics'&gt;GoodData: One Stop Shop for Analytics&lt;/a&gt;&lt;/strong&gt;&lt;object id='__sse6054703' height='355' width='425'&gt;&lt;param name='movie' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=onestopshopforanalytics-101206180841-phpapp01&amp;amp;stripped_title=one-stopshopforanalytics&amp;amp;userName=jakub.nesetril' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowScriptAccess' value='always' /&gt;&lt;embed name='__sse6054703' src='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=onestopshopforanalytics-101206180841-phpapp01&amp;amp;stripped_title=one-stopshopforanalytics&amp;amp;userName=jakub.nesetril' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='355' width='425' /&gt;&lt;/object&gt;&lt;div style='padding:5px 0 12px'&gt;View more &lt;a href='http://www.slideshare.net/'&gt;presentations&lt;/a&gt; from &lt;a href='http://www.slideshare.net/jakub.nesetril'&gt;Jakub Nešetřil&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;
&lt;h3 id='business_intelligence_platform_as_a_service_introduction_to_gooddata'&gt;Business Intelligence Platform as a Service: Introduction to GoodData&lt;/h3&gt;

&lt;p&gt;Peter Olmer presentation about GoodData Platform as a Service.&lt;/p&gt;
&lt;div id='__ss_6054797' style='width:425px'&gt;&lt;strong style='display:block;margin:12px 0 4px'&gt;&lt;a href='http://www.slideshare.net/petrolmer/business-intelligence-platform-as-a-service-introduction-to-gooddata' title='Business Intelligence Platform as a Service: Introduction to GoodData'&gt;Business Intelligence Platform as a Service: Introduction to GoodData&lt;/a&gt;&lt;/strong&gt;&lt;object id='__sse6054797' height='355' width='425'&gt;&lt;param name='movie' value='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=bipaaspublic-101206182223-phpapp01&amp;amp;stripped_title=business-intelligence-platform-as-a-service-introduction-to-gooddata&amp;amp;userName=petrolmer' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowScriptAccess' value='always' /&gt;&lt;embed name='__sse6054797' src='http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=bipaaspublic-101206182223-phpapp01&amp;amp;stripped_title=business-intelligence-platform-as-a-service-introduction-to-gooddata&amp;amp;userName=petrolmer' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='355' width='425' /&gt;&lt;/object&gt;&lt;div style='padding:5px 0 12px'&gt;View more &lt;a href='http://www.slideshare.net/'&gt;presentations&lt;/a&gt; from &lt;a href='http://www.slideshare.net/petrolmer'&gt;Petr Olmer&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/45gF48vxDXU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/12/02/slides-from-cloudstock-sessions</feedburner:origLink></entry>
 
 <entry>
   <title>Cloudstock talk: BI Platform as a Service</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/rcx5EaHjalc/cloudstock-bi-platform-as-a-service" />
   <updated>2010-12-02T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2010/12/02/cloudstock-bi-platform-as-a-service</id>
   <content type="html">&lt;h1 id='cloudstock_talk_bi_platform_as_a_service'&gt;Cloudstock talk: BI Platform as a Service&lt;/h1&gt;

&lt;p&gt;Our evangelist Petr Olmer will talk about GoodData at &lt;a href='http://www.cloudstockevent.com/'&gt;Cloudstock&lt;/a&gt; on Monday, December 6. If you wonder what will be covered, here&amp;#8217;s the revealing mind map. Are you thinking about working with GoodData? Be at the session or talk to us at our demo pod.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/BI_PAAS.png' alt='mindmap' /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href='http://blog.cloudstockevent.com/blog/2010/11/meet-analytics-in-the-cloud/'&gt;Read more about GoodData sessions at Cloudstock&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/rcx5EaHjalc" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/12/02/cloudstock-bi-platform-as-a-service</feedburner:origLink></entry>
 
 <entry>
   <title>Cloudstock Hackathon - Start Your Keyboards</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/zrNm4XothKk/cloudstock" />
   <updated>2010-12-01T00:00:00-08:00</updated>
   <id>http://developer.gooddata.com/blog/2010/12/01/cloudstock</id>
   <content type="html">&lt;h1 id='cloudstock_hackathon__start_your_keyboards'&gt;Cloudstock Hackathon - Start Your Keyboards&lt;/h1&gt;
&lt;img title='CloudStock iPhone' src='/images/posts/cloudstock-iphone.png' align='right' alt='CloudStock iPhone' style='border: 0px; margin-left: 20px; margin-top: 40px;' /&gt;
&lt;p&gt;Next week 5000 developers are going to descend on San Francisco to take part in CloudStock - the premier event for cloud application developers. And to amplify the fun, you can compete in CloudStock hackathon for one of &lt;a href='http://www.cloudstockevent.com/cloudstockhackathon'&gt;many prizes&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='start_hacking_now'&gt;Start hacking now!&lt;/h2&gt;

&lt;p&gt;You can win a iPod touch 32GB for the &amp;#8220;Best Analytic Innovation&amp;#8221; prize sponsored by GoodData. So get working now. Here is a short jump-start guide to get you running quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;register for a &lt;a href='https://secure.gooddata.com/registration.html'&gt;free account&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;we&amp;#8217;ve created a command-line utility called &lt;a href='/gooddata-cl'&gt;GoodData CL&lt;/a&gt; to help you use GoodData APIs&lt;/li&gt;

&lt;li&gt;watch this &lt;a href='http://developer.gooddata.com/start/load-in-5-minutes.html'&gt;quick screencast&lt;/a&gt; showing you a setup of a sample analytical project (follow the text along, download all the sample scripts)&lt;/li&gt;

&lt;li&gt;here&amp;#8217;s a bit &lt;a href='http://developer.gooddata.com/start/'&gt;more background&lt;/a&gt; on what&amp;#8217;s happening under-the-hood&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give us a shout at &lt;a href='http://twitter.com/gooddata_dev'&gt;@gooddata_dev&lt;/a&gt; if you have any questions, or our &lt;a href='http://support.gooddata.com/forums/176660-developer-forum'&gt;Developer Forum&lt;/a&gt;. We&amp;#8217;ll be focusing heavily to help you move quickly.&lt;/p&gt;

&lt;p&gt;And of course, come see us on CloudStock. We&amp;#8217;ll be both manning the booth and roaming the hackathon, some of our best developers giving you hands-on support on the spot. We&amp;#8217;re excited to see what you come up with!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/zrNm4XothKk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/12/01/cloudstock</feedburner:origLink></entry>
 
 <entry>
   <title>Automated Notifications and Messages from GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/6ERurkgQI_c/automated-notifications-messages" />
   <updated>2010-11-02T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/11/02/automated-notifications-messages</id>
   <content type="html">&lt;h1 id='automated_notifications_and_messages_from_gooddata'&gt;Automated Notifications and Messages from GoodData&lt;/h1&gt;

&lt;p&gt;We&amp;#8217;ve created a new tool designed to monitor GoodData reports - and if certain conditions are met, to send a message to another system. It was design for the purpose of Salesforce Chatter integration, but could conceivably be used with Yammer, Twitter or other messaging systems.&lt;/p&gt;
&lt;div style='text-align: center;'&gt;&lt;img src='/images/posts/chatter.png' alt='Chatter Demo' style='border: 0px none;' /&gt;&lt;/div&gt;
&lt;p&gt;Here is a beta download: (&lt;a href='http://support.gooddata.com/attachments/token/y9oxeyrfytglxi5/?name=gooddata-alert-1.2.2-SNAPSHOT.tar.gz'&gt;tar.gz&lt;/a&gt;, &lt;a href='http://support.gooddata.com/attachments/token/eb2aklrvb5ldgbz/?name=gooddata-alert-1.2.2-SNAPSHOT.zip'&gt;zip&lt;/a&gt;). The tool has many similarities with GoodData CL. Documentation and examples are included in the download, however here are links to view them online:&lt;/p&gt;

&lt;p&gt;&lt;a href='http://github.com/gooddata/GoodData-CL/tree/sli/notification-distro/#readme'&gt;Installation&lt;/a&gt;&lt;br /&gt;&lt;a href='http://github.com/gooddata/GoodData-CL/blob/sli/notification-distro/doc/XML.md#readme'&gt;Config XML Documentation&lt;/a&gt;&lt;br /&gt;&lt;a href='http://github.com/gooddata/GoodData-CL/tree/sli/notification-distro/examples/sfdc-chatter/#readme'&gt;Salesforce Chatter Example&lt;/a&gt;&lt;/p&gt;

&lt;h1 id='building_your_own_messaging_connectors'&gt;Building Your Own Messaging Connectors&lt;/h1&gt;

&lt;p&gt;The core of GoodData Notification tool is shared with GoodData CL. If you want to try building your own connector into a different messaging service, follow the &lt;a href='http://github.com/gooddata/GoodData-CL#readme'&gt;instructions on how to build GoodData CL&lt;/a&gt;, but in step 6, instead of doing &lt;code&gt;cd cli-distro&lt;/code&gt;, use instead the notification-distro: &lt;code&gt;cd notification-distro&lt;/code&gt; and then resume the original instructions with &lt;code&gt;mvn assembly:assembly&lt;/code&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/6ERurkgQI_c" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/11/02/automated-notifications-messages</feedburner:origLink></entry>
 
 <entry>
   <title>Google Analytics Connector Now Supports Multiple Profiles</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/3Uaj37NYta0/google-analytics-multiple-profiles" />
   <updated>2010-10-26T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/10/26/google-analytics-multiple-profiles</id>
   <content type="html">&lt;h1 id='google_analytics_connector_now_supports_multiple_profiles'&gt;Google Analytics Connector Now Supports Multiple Profiles&lt;/h1&gt;

&lt;p&gt;Based on popular demand, the new &lt;a href='/blog/2010/10/15/data-upload-apis/'&gt;CL tool v1.2&lt;/a&gt; contains an updated version of Google Analytics connector which supports multiple Google Analytics profiles (and thus the ability to analyze multiple different websites).&lt;/p&gt;

&lt;p&gt;The new connector uses the same old Google Analytics project template. Thus, once your create the project from the template, you&amp;#8217;ll need to run a simple MAQL DDL script to extend the data model with the multi-profile extensions. You&amp;#8217;ll also need to create a simple CSV that lists all profiles that you want to load to GoodData and load it to the project as additional dataset.&lt;/p&gt;

&lt;p&gt;For more detailed instructions, see the end of the &lt;a href='http://github.com/gooddata/GoodData-CL/tree/sli/cli-distro/examples/ga/'&gt;GA connector README&lt;/a&gt;. &lt;strong&gt;Note&lt;/strong&gt;: you have to use the &lt;a href='/blog/2010/10/15/data-upload-apis/'&gt;GoodData CL v1.2&lt;/a&gt; &amp;#8211; currently in alpha build.&lt;/p&gt;
&lt;table cellspacing='0' border='1' cellpadding='5'&gt;
    &lt;tr&gt;&lt;th&gt;profileId&lt;/th&gt;&lt;th&gt;profileName&lt;/th&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;ga:7654321&lt;/td&gt;&lt;td&gt;Example Site&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;ga:1234567&lt;/td&gt;&lt;td&gt;Second Site&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The Google Analytics dashboards need a bit work to better support multiple profiles. Can you help us improve it? &lt;a href='mailto:support@gooddata.com'&gt;Drop us a note&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/3Uaj37NYta0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/10/26/google-analytics-multiple-profiles</feedburner:origLink></entry>
 
 <entry>
   <title>GoodData CL 1.1 to 1.2 Migration</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/5PG49ekivg4/gooddata-cl-migration" />
   <updated>2010-10-25T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/10/25/gooddata-cl-migration</id>
   <content type="html">&lt;h1 id='upgrading_projects_created_with_cl_tool_11_to_cl_tool_12'&gt;Upgrading projects created with CL tool 1.1 to CL tool 1.2&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Note: This is a follow-up blog post to our &lt;a href='/blog/2010/10/15/data-upload-apis/'&gt;recent post about new SLI APIs&lt;/a&gt; and new CL tool version.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The new 1.2 version of CL tool changes the way data models are being created. This new version changes the way data models are being created. This requires a simple migration of projects created with CL tool 1.1 and older.&lt;/p&gt;

&lt;p&gt;Only projects that use datasets without any facts require the migration. If you try to load data to such project, you&amp;#8217;ll most probably receive an error reading &amp;#8220;Unknown import mode&amp;#8221; or complaints about non-existing &lt;code&gt;factsof&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;If your project requires migration, you&amp;#8217;ll need to execute a migration MAQL script via the &lt;code&gt;ExecuteMaql&lt;/code&gt; command. The migration script deletes the ambiguous &lt;code&gt;factsof&lt;/code&gt; attribute that has been created for the dataset&amp;#8217;s &lt;code&gt;CONNECTION POINT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll need to run the &lt;code&gt;ALTER ATTRIBUTE&lt;/code&gt; statement on the line 5 for every &lt;code&gt;REFERENCE&lt;/code&gt; to the migrated dataset. You&amp;#8217;ll also need to &lt;code&gt;SYNCHRONIZE&lt;/code&gt; all &lt;code&gt;REFERENCE&lt;/code&gt; datasets.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.&amp;lt;connection-point-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{f_&amp;lt;dataset-name&amp;gt;.id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;DATASET&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;dataset-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;# You need to add this statement for each REFERENCE to the migrated dataset&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.&amp;lt;dataset-name&amp;gt;.&amp;lt;connection-point-name&amp;gt;}&lt;/span&gt; &lt;span class='k'&gt;ADD&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt;
    &lt;span class='nv'&gt;{d_&amp;lt;reference-dataset-name&amp;gt;_&amp;lt;reference-name&amp;gt;.&amp;lt;dataset-name&amp;gt;_id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;dataset-name&amp;gt;}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Also you need to synchronize all REFERENCE datasets&lt;/span&gt;
&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.&amp;lt;reference-dataset-name&amp;gt;}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let me illustrate this on the HR demo project. There are two datasets with no facts: department, and employee. The following figure highlights the &lt;code&gt;factsof&lt;/code&gt; attributes that we need to delete and reconnect.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/old.model.png' alt='Old Model' /&gt;&lt;/p&gt;

&lt;p&gt;and here is the new model that we need to create&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/posts/new.model.png' alt='New Model' /&gt;&lt;/p&gt;

&lt;p&gt;Here is the script that updates both department and employee datasets.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='c1'&gt;# Disconnect the department attribute from the department factsof that we are going to drop&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.department.department}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{f_department.id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Remove the department factsof from the department dataset&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;DATASET&lt;/span&gt; &lt;span class='nv'&gt;{dataset.department}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.department.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Drop the department factsof&lt;/span&gt;
&lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.department.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;# Disconnect the employee attribute from the employee factsof that we are going to drop&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.employee.employee}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{f_employee.id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Remove the employee factsof from the employee dataset&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;DATASET&lt;/span&gt; &lt;span class='nv'&gt;{dataset.employee}&lt;/span&gt; &lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.employee.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Drop the employee factsof&lt;/span&gt;
&lt;span class='k'&gt;DROP&lt;/span&gt; &lt;span class='nv'&gt;{attr.employee.factsof}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;# Reconnect the department attribute to the employee (bridge the non-existing factsof)&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.department.department}&lt;/span&gt; &lt;span class='k'&gt;ADD&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{d_employee_employee.department_id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='c1'&gt;# Reconnect the employee attribute to the employee (bridge the non-existing factsof)&lt;/span&gt;
&lt;span class='k'&gt;ALTER&lt;/span&gt; &lt;span class='k'&gt;ATTRIBUTE&lt;/span&gt; &lt;span class='nv'&gt;{attr.employee.employee}&lt;/span&gt; &lt;span class='k'&gt;ADD&lt;/span&gt; &lt;span class='k'&gt;KEYS&lt;/span&gt; &lt;span class='nv'&gt;{f_salary.employee_id}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;# Synchronize the model changes with the underlying storage&lt;/span&gt;
&lt;span class='c1'&gt;# Please note that currently all data will be deleted after running the SYNCHRONIZE command!&lt;/span&gt;
&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.department}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.employee}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;SYNCHRONIZE&lt;/span&gt; &lt;span class='nv'&gt;{dataset.salary}&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Caution:&lt;/em&gt; The &lt;code&gt;SYNCHRONIZE&lt;/code&gt; statement will delete all data from the given server-side data set. You will need to perform a full load after issuing the statements above!&lt;/p&gt;

&lt;p&gt;You need to create your migration script, save it in a &lt;code&gt;migrate.maql&lt;/code&gt; file, and create the migration commands file that opens the migrated project and execute the migration MAQL.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='c1'&gt;# Open the migrated project&lt;/span&gt;
&lt;span class='nf'&gt;OpenProject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;id&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;&amp;lt;your-migrated-project-hash&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='c1'&gt;# Execute the MAQL&lt;/span&gt;
&lt;span class='nf'&gt;ExecuteMaql&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;maqlFile&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;migrate.maql&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, you will need to run your data loading script to re-populate the data sets as their contents have been deleted by the &lt;code&gt;SYNCHRONIZE&lt;/code&gt; MAQL statement.&lt;/p&gt;

&lt;p&gt;The other option is to start from scratch and create entirely new project from the new CL tool version. The new project obviously doesn&amp;#8217;t contain the reports and dashboards that you might have in your current project. You can use the new &lt;code&gt;RetrieveAllObjects&lt;/code&gt; CL tool command to retrieve all objects from the old project to your disk and then CopyObjects command to copy these objects to your new project. You&amp;#8217;ll need to delete the &lt;code&gt;factsof&lt;/code&gt; objects from the disk before the import.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/5PG49ekivg4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/10/25/gooddata-cl-migration</feedburner:origLink></entry>
 
 <entry>
   <title>Numbers &amp; Arrows in Dashboards</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/8KK7OLvAeCA/numbers-trends-on-dashboard" />
   <updated>2010-10-19T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/10/19/numbers-trends-on-dashboard</id>
   <content type="html">&lt;h1 id='numbers__arrows_in_dashboards'&gt;Numbers &amp;#38; Arrows in Dashboards&lt;/h1&gt;

&lt;p&gt;Some of you have written in and asked how we achieved our nice &lt;a href='http://www.gooddata.com/blog/get-satisfaction-and-gooddata-team-up-to-transform-social-engagement-metrics/'&gt;GetSatisfaction health dashboards&lt;/a&gt; with large numbers visual and progress indicators. Since this is a bit of a hack, I decided this would be a good audience to explain the trick. We do intend to implement this feature properly - in about a month. However, in the mean time, some clever tricks / a bit of wrestling can get you this effect today: &lt;img src='http://www.gooddata.com/files/2010/10/GetSatisfaction-Dashboard.jpg' alt='Custom Arrows Formatting' /&gt;&lt;/p&gt;

&lt;h3 id='large_font_numeric_report'&gt;Large Font Numeric Report:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a report showing a single number (remove all attributes in the How section)&lt;/li&gt;

&lt;li&gt;Convert the report to a stack bar chart&lt;/li&gt;

&lt;li&gt;In the right column &amp;gt; &lt;strong&gt;Advanced Configuration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Y Axis&lt;/strong&gt; &amp;gt; &lt;strong&gt;Primary Axis&lt;/strong&gt;, set the &lt;strong&gt;max&lt;/strong&gt; of the axis to something several orders of magnitude larger then your data - for example 1000000000 (depending on your number), and untick the &lt;strong&gt;Name&lt;/strong&gt; and &lt;strong&gt;Labels&lt;/strong&gt; checkboxes&lt;/li&gt;

&lt;li&gt;In Advanced Configuration &amp;gt; Global Settings, make sure &lt;strong&gt;Data Labels&lt;/strong&gt; is checked, set the font size to 18, turn off &lt;strong&gt;Values&lt;/strong&gt; and &lt;strong&gt;Boxed&lt;/strong&gt;, but keep &lt;strong&gt;Totals&lt;/strong&gt; &lt;p&gt;&lt;img src='/images/posts/chart-settings.png' alt='Chart Settings' /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id='trending_colored_arrows'&gt;Trending Colored Arrows:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;To show a positive/negative trend, you need to create a second metric showing a difference in time. Here is a MAQL example for a metric called &lt;code&gt;Revenue&lt;/code&gt;, showing trend between last month and the month before it (attribute &lt;code&gt;Month&lt;/code&gt;): &lt;pre&gt;&lt;code&gt;SELECT (SELECT Revenue WHERE Month/Year = {Previous} )
 - (SELECT Revenue WHERE Month/Year = {Previous}-1)&lt;/code&gt;&lt;/pre&gt; You will need to create this as a &lt;a href='https://secure.gooddata.com/docs/html/reference.guide.createmetrics.advancedMetricEditor.html#reference.guide.createmetrics.advanced.custom'&gt;Advanced Custom Metric&lt;/a&gt;. See more documentation on &lt;a href='https://secure.gooddata.com/docs/html/reference.guide.maql.previousPeriod.html'&gt;floating date metrics&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;Create a customized formatting for this metric. Here&amp;#8217;s where the trick get&amp;#8217;s a bit hairy, full documentation is &lt;a href='https://secure.gooddata.com/docs/html/reference.guide.reportoptions.formatting.html'&gt;available here&lt;/a&gt;. We&amp;#8217;re using both conditional formatting (different for negative and positive numbers) and changing the font color. For the final trick, we provide a Unicode symbol for up/down arrow. The final formatting string looks like this:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;[green]▲;[red]▼&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src='/images/posts/custom-arrows-formatting.png' alt='Custom Arrows Formatting' /&gt;&lt;/p&gt;
&lt;p&gt;You can choose your own symbols/arrows, for example by copy/pasting them from Wikipedia (&lt;a href='http://en.wikipedia.org/wiki/Geometric_shapes'&gt;shapes&lt;/a&gt;, &lt;a href='http://en.wikipedia.org/wiki/Arrow_%28symbol%29'&gt;arrows&lt;/a&gt;).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/8KK7OLvAeCA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/10/19/numbers-trends-on-dashboard</feedburner:origLink></entry>
 
 <entry>
   <title>Update on Data Upload APIs (and CL tool v1.2)</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/EHWxxntBPAg/data-upload-apis" />
   <updated>2010-10-15T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/10/15/data-upload-apis</id>
   <content type="html">&lt;h1 id='on_data_upload_apis_and_cl_tool_v12'&gt;On Data Upload APIs (and CL tool v1.2)&lt;/h1&gt;

&lt;p&gt;We&amp;#8217;ve been really busy in GoodData in the past couple months reshaping our upload APIs - simplifying them, speeding them up and opening them up to more flexibility. Our v1.0 API allowed you to upload a single CSV file and our product would try to infer the data model from it (giving you a few couple options to choose from along the way).&lt;/p&gt;

&lt;p&gt;We soon realized that we needed a more powerful data framework - but more importantly that we need to turn the table and allow you to specify a data model first and for the data interface to follow later. We have created v2.0 of our APIs that allowed you the tremendous flexibility to create your own data model explicitly.&lt;/p&gt;

&lt;p&gt;To speed things up and get this out of the door ASAP, we had to sacrifice a bit of simplicity. Our APIs would accept data only in a normalized form, each lookup in a separate data file. We called these APIs &amp;#8220;DLI&amp;#8221; (shorthand for data-loading interface) and quickly built a bit of magic into CL tool to produce these normalized files automatically for you. CL tool was either using built-in Apache Derby or external MySQL to transform and normalize the data.&lt;/p&gt;

&lt;p&gt;Today we&amp;#8217;ve finally finished our last piece of the Data Upload API puzzle - SLI (single-file loading interface). You can still specify your own data model, but we give you a single data file to load and do all the normalization inside the product. This both simplifies the upload and speeds it up significantly (compared to the existing CL tool with DLI APIs).&lt;/p&gt;

&lt;p&gt;Currently, the new version of CL tool using these APIs is a special build. Once we test everything works as expected, we&amp;#8217;ll turn on SLI APIs for everybody.&lt;/p&gt;

&lt;h3 id='whats_changing_with_slis'&gt;What&amp;#8217;s changing with SLIs:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CL tool doesn&amp;#8217;t need any DB backend (Derby or MySQL)&lt;/li&gt;

&lt;li&gt;Uploads processing should be significantly faster&lt;/li&gt;

&lt;li&gt;GoodData CL (and other API clients) can be significantly simplified&lt;/li&gt;

&lt;li&gt;You can upload into one project from different computers (no single CL tool instance necessary)&lt;/li&gt;

&lt;li&gt;You cannot mix&amp;#38;match DLI and SLI in single project. You can only use one or the other.&lt;/li&gt;

&lt;li&gt;You need a special CL tool build (currently, eventually we&amp;#8217;ll migrate all projects)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;-b, -c, -d, -m&lt;/code&gt; (or &lt;code&gt;--backend, --dbusername, --dbpassword&lt;/code&gt; and &lt;code&gt;--memory&lt;/code&gt;) CL flags are meaning less&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;#8217;d like you to help us prototype the new APIs. If you&amp;#8217;re interested, download &lt;a href='http://support.gooddata.com/entries/330347-gooddata-cl-1-2-sli-alpha-build'&gt;this special build&lt;/a&gt;. If you run into issues, let us know on &lt;a href='http://support.gooddata.com/forums/176660-developer-forum'&gt;Developer Forum&lt;/a&gt; (and please indicate you&amp;#8217;re using SLI APIs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; for existing projects created with CL tool 1.1, a migration process might be necessary. Read the &lt;a href='/blog/2010/10/25/gooddata-cl-migration/'&gt;follow-up blog post&lt;/a&gt; for details.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/EHWxxntBPAg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/10/15/data-upload-apis</feedburner:origLink></entry>
 
 <entry>
   <title>How to Load Date Dimension into GoodData</title>
   <link href="http://feedproxy.google.com/~r/gooddata-developer-blog/~3/tjDiScu132I/loading-date-dimension" />
   <updated>2010-10-14T00:00:00-07:00</updated>
   <id>http://developer.gooddata.com/blog/2010/10/14/loading-date-dimension</id>
   <content type="html">&lt;h1 id='how_to_load_date_dimension_into_gooddata'&gt;How to Load Date Dimension into GoodData&lt;/h1&gt;

&lt;p&gt;GoodData allows you to use it&amp;#8217;s built-in provided date dimension. Using this dimension organizes days into weeks, months, weekdays/weekend etc. Here is a step-by-step tutorial on how to setup data model for the dimension, load it into your project and map your data to it.&lt;/p&gt;
&lt;object id='date-dimension' height='500' align='middle' classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0' width='800' style='margin: 40px 0px; display: block;'&gt;
&lt;param name='allowScriptAccess' value='sameDomain' /&gt;
&lt;param name='movie' value='/images/date-dimension.swf' /&gt;
&lt;param name='quality' value='high' /&gt;
&lt;param name='bgcolor' value='#000000' /&gt;
&lt;embed name='date-dimension' src='/images/date-dimension.swf' allowScriptAccess='sameDomain' pluginspage='http://www.macromedia.com/go/getflashplayer' type='application/x-shockwave-flash' height='500' align='middle' quality='high' bgcolor='#000000' width='800' /&gt;
&lt;/object&gt;&lt;img src="http://feeds.feedburner.com/~r/gooddata-developer-blog/~4/tjDiScu132I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://developer.gooddata.com/blog/2010/10/14/loading-date-dimension</feedburner:origLink></entry>
 
 
</feed>

