<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>If &amp; Else</title>
	
	<link>http://ifandelse.com</link>
	<description>Straddling the fence between application and database development...</description>
	<lastBuildDate>Tue, 06 Jul 2010 04:39:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ifandelse/feed" /><feedburner:info uri="ifandelse/feed" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>CouchRS – Creating SSRS Reports against CouchDB Views</title>
		<link>http://feedproxy.google.com/~r/ifandelse/feed/~3/tbGackUF4Xw/</link>
		<comments>http://ifandelse.com/2010/07/05/couchrs-creating-ssrs-reports-against-couchdb-views/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 03:11:07 +0000</pubDate>
		<dc:creator>Jim Cowart</dc:creator>
				<category><![CDATA[Business Intelligence]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[CouchRS]]></category>
		<category><![CDATA[MapReduce]]></category>

		<guid isPermaLink="false">http://ifandelse.com/2010/07/05/couchrs-creating-ssrs-reports-against-couchdb-views/</guid>
		<description><![CDATA[In my previous post we looked at how to build a simple report in SQL Reporting Services using CouchDB as the backend.&#160; While reports against a single CouchDB document might useful in some instances, the real power comes into play when you are querying CouchDB views.&#160; (Refer to my introductory post and to “CouchRS – [...]]]></description>
			<content:encoded><![CDATA[<p><font face="Tahoma">In my previous post we looked at how to build a simple report in SQL Reporting Services using CouchDB as the backend.&#160; While reports against a single CouchDB document might useful in some instances, the real power comes into play when you are querying CouchDB views.&#160; (Refer to my </font><a href="http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/" target="_blank"><font face="Tahoma">introductory post</font></a><font face="Tahoma"> and to “</font><a href="http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/" target="_blank"><font face="Tahoma">CouchRS – Building Your First Report…</font></a><font face="Tahoma">” for examples on how to install CouchRS, and how to configure a Reporting Services project Data Source and Dataset to use CouchRS.)</font></p>
<p><font face="Tahoma">In order for us to query a CouchDB view, we need to create one.&#160; You can edit CouchDB views directly in the Futon web interface, but I’m using “</font><a href="http://www.russiantequila.com/wordpress/?p=119" target="_blank"><font face="Tahoma">LoveSeat</font></a><font face="Tahoma">” – an open source editor for CouchDB.&#160; The data I’m using is a subset of the AdventureWorks2008R2 database, loaded into Couch.&#160; To simplify things, my object model consists of Customers, who have Orders, and Orders have OrderDetails.&#160; Each document in my CouchDB is a Customer object.&#160; The point here is to illustrate that you can use CouchDB to store your domain model aggregate root(s), and still perform a wide range of reporting against this data without the need for it to be stored relationally.</font></p>
<p><font face="Tahoma">So, for our first view, let’s create something that returns territory and total sales information.&#160; Each order in my object model has a “Territory” object, and I’d like to include the Territory’s “GroupName”, “CountryRegionCode” and “Name” in my view, along with the year and month of each Order, and the “TotalDue” amount of each order.&#160; Here’s a screen shot of my “map” function for this view:</font></p>
<p align="center"><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/ViewJS1.png"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="View JS 1" border="0" alt="View JS 1" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/ViewJS1_thumb.png" width="244" height="198" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">This function takes a document as its argument (map functions are called for each document in the database).&#160; Then we iterate over the Orders collection for the given document and emit a record that has an array key of [GroupName, CountryRegionCode, Name, Year, Month] and a value equal to the “TotalDue” for that Order.&#160; Note that this mapping function can emit <em>multiple</em> records per document passed to it.&#160; If we query this view via a browser, we’ll see results similar to this:</font></p>
<p><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/SampleViewResults1.png"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Sample View Results 1" border="0" alt="Sample View Results 1" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/SampleViewResults1_thumb.png" width="592" height="318" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma">Once this view has been built and queried for the first time, subsequent requests are instantaneously answered.&#160; We could go ahead and use this data to drive our report, but I want to take advantage of another feature of CouchDB views, the ”reduce” function.&#160; The reduce function on a Couch view is called on the set of data produced by the view.&#160; In our case, it can be used to aggregate the data by the key or even just a portion of the key.&#160; This reduce function in this example reads:</font></p>
<p align="center"><font size="3"><font face="Tahoma"><font color="#0000ff">function</font>(keys,values) { <font color="#0000ff">return</font> sum(values); }</font></font></p>
<p align="left"><font face="Tahoma">This function aggregates (sums) the value (“TotalDue”, in our case) by the key.&#160; If you’re wondering why I made the key complex, and the value scalar, it’s because I wanted to take advantage of the “reduce” (</font><a href="http://books.couchdb.org/relax/reference/views-for-sql-jockeys" target="_blank"><font face="Tahoma">reduce functions should, as a general rule, return a scalar value</font></a><font face="Tahoma">).&#160; Fairly simple stuff, right?&#160; Later on, we’ll touch on how “SeeNoSQL” supports CouchDB’s </font><a href="http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options" target="_blank"><font face="Tahoma">query options</font></a><font face="Tahoma">, enabling us to specify a “group_level” on a reduced view, effectively allowing us to aggregate the values by partial keys (i.e. – what if you wanted see the totals for all regions by year, and leave “month” out of it?).</font></p>
<p align="left"><font face="Tahoma">Now that we have a reduced view, let’s open a new report up and create a data set that points to our view:</font></p>
<p align="left"><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/FROMVIEWDataSet.png"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="FROM VIEW - DataSet" border="0" alt="FROM VIEW - DataSet" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/FROMVIEWDataSet_thumb.png" width="613" height="494" /></font></a></p>
<p><font face="Tahoma">The command text presented here has quite a bit more going on that our easy example from my </font><a href="http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/" target="_blank"><font face="Tahoma">last post</font></a><font face="Tahoma">:</font></p>
<ul>
<li><font face="Tahoma"><strong>FROM VIEW(aw,sales_by_region_year_month)</strong> – indicates we’re querying a view.&#160; The first argument of the VIEW() function is the name of the design document that the view resides in, and the second argument is the name of the view. </font></li>
<li><font face="Tahoma"><strong>USING QUERYOPTIONS(Group=true)</strong> – this tells Couch to Group the results by the full key, otherwise we’d get a result set with only one record that summed all the values in the view (we have to include this because this view has a “reduce” function &#8211; this isn’t necessary for non-reduced views).&#160; Other query options that can be used here are: </font>
<ul>
<li><font face="Tahoma"><strong>ALLOW_STALE</strong> (true/false) – if true, CouchDB will not refresh the view even if it is stalled. </font></li>
<li><font face="Tahoma"><strong>DESCENDING</strong> (true/false) – if true, the results are sorted in descending order by the key. </font></li>
<li><font face="Tahoma"><strong>GROUP_LEVEL</strong> (int) – the level at which to group the results.&#160; We have a 5 part key, so, a group level of 3 would only group it to the third key (GroupName, CountryRegionCode, Name), a group value of 4 would group it up to GroupName, CountryRegionCode, Name &amp; Year, etc. </font></li>
<li><font face="Tahoma"><strong>INCLUDE_DOCS</strong> (true/false) – if true, it includes the original document that was used to emit the record in the view. </font></li>
<li><font face="Tahoma"><strong>INCLUSIVE_END</strong> (true/false) – Controls whether the endkey is included in the result. </font></li>
<li><font face="Tahoma"><strong>REDUCE</strong> (true/false) – if false, the reduce function in a view is not executed. </font></li>
<li><font face="Tahoma"><strong>SKIP</strong> (int) – skips the number of rows specified. </font></li>
<li><font face="Tahoma"><strong>LIMIT</strong> (int) – limits the number of results returned to the number specified. </font></li>
</ul>
</li>
<li><font face="Tahoma"><strong>WITH KEY[GroupName,CountryCode,Country,Year,Month]</strong> – this tells the SeeNoSQL parser that you are using a view with an array key with 5 elements.&#160; You can call each element whatever you want for the sake of the query, as long as you understand that they are evaluated in the same order that the actual key is in.&#160; If you don’t have a WHERE clause, the “WITH KEY” statement is not required. </font></li>
<li><font face="Tahoma"><strong>WHERE Year = @Year          <br />AND Month BETWEEN(@StartMonth,@EndMonth)           <br />AND GroupName BETWEEN(MIN_STRING,MAX_STRING)           <br />AND CountryCode BETWEEN(MIN_STRING,MAX_STRING)           <br />AND Country BETWEEN(MIN_STRING,MAX_STRING)</strong> – This specifies that user-driven parameters will provide the value for Year, and a range for month.&#160; For the sake of this report, though, we don’t want to constrain the region information.&#160; SeeNoSQL supports a “MIN_STRING” and “MAX_STRING” constant that, when evaluated and sent to Couch, corresponds to null and {} (empty object).&#160; Submitting a range like this will return any string value in the key. </font></li>
</ul>
<p><font face="Tahoma">(For more information on the CouchDB View API, check out the CouchDB </font><a href="http://wiki.apache.org/couchdb/HTTP_view_API" target="_blank"><font face="Tahoma">wiki</font></a><font face="Tahoma"> and the “</font><a href="http://books.couchdb.org/relax/reference/views-for-sql-jockeys" target="_blank"><font face="Tahoma">View Cookbook for SQL Jockeys</font></a><font face="Tahoma">”.)</font></p>
<p><font face="Tahoma">If we click the “Query Designer” button and execute the query, we’ll get results similar to:</font></p>
<p align="center"><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/QueryDesigner.png"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Query Designer" border="0" alt="Query Designer" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/QueryDesigner_thumb.png" width="616" height="466" /></font></a><font face="Tahoma">      <br /></font></p>
<p><font face="Tahoma">Notice that CouchRS has broken the array key into separate fields.&#160; (In future versions of CouchRS, I plan to have it name the fields for you based on how you aliased them in the command text.&#160; If you use an object key, it already names the fields using the field names on the object).&#160; Although I could work with fields named “key0”, “key1”, etc., I’ve chosen to rename mine to make things more intuitive while building the report:</font></p>
<p><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/FieldProperties.png"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Field Properties" border="0" alt="Field Properties" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/FieldProperties_thumb.png" width="611" height="477" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">In the sample reports project (included in the </font><a href="http://github.com/ashbylane/CouchRS" target="_blank"><font face="Tahoma">GitHub</font></a><font face="Tahoma"> repository), the above query drives the data for the “Territory Group Sales by Year” report:</font></p>
<p><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/TerritoryGroupSalesbyYear.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Territory Group Sales by Year" border="0" alt="Territory Group Sales by Year" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/TerritoryGroupSalesbyYear_thumb.jpg" width="617" height="604" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">And page 2 of the sample report:</font></p>
<p><a href="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/TerritoryGroupSalesbyYear2.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Territory Group Sales by Year 2" border="0" alt="Territory Group Sales by Year 2" src="http://ifandelse.com/img/posts/f94ef15623e5_DAAC/TerritoryGroupSalesbyYear2_thumb.jpg" width="617" height="631" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">Ok – so it’s very easy to get charted reports up and running against CouchDB.&#160; One key thing to bear in mind is that since the results from Couch are returned to CouchRS as JSON, all the values are treated as <em>text</em>.&#160; This means you will most likely have to convert numeric &amp; date values to their respective types as you use them (I had to use CDec() and CInt() in these reports in order to properly format currency and to properly sort by month).</font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma">However – what if you wanted to compare a given region against the average of the other regions? Or in the case of a customer, see where they fall compared to the average customer?&#160; Stay tuned….we’ll cover that in the next post….</font></p>
<p><font face="Tahoma"></font></p>
<img src="http://feeds.feedburner.com/~r/ifandelse/feed/~4/tbGackUF4Xw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ifandelse.com/2010/07/05/couchrs-creating-ssrs-reports-against-couchdb-views/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://ifandelse.com/2010/07/05/couchrs-creating-ssrs-reports-against-couchdb-views/</feedburner:origLink></item>
		<item>
		<title>CouchRS – Building Your First Report against CouchDB using SSRS</title>
		<link>http://feedproxy.google.com/~r/ifandelse/feed/~3/39z8rBL_RTo/</link>
		<comments>http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/#comments</comments>
		<pubDate>Sun, 04 Jul 2010 07:21:40 +0000</pubDate>
		<dc:creator>Jim Cowart</dc:creator>
				<category><![CDATA[Business Intelligence]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[CouchRS]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[SSRS]]></category>

		<guid isPermaLink="false">http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/</guid>
		<description><![CDATA[In my introductory post for CouchRS, I explained where to get the code and how to install the custom processing extension.&#160; Now that you have CouchRS installed, let’s look at a very simple example on how to use it. In Visual Studio 2008, our first step is to create a new Report Server project and [...]]]></description>
			<content:encoded><![CDATA[<p><font face="Tahoma">In my </font><a href="http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/" target="_blank"><font face="Tahoma">introductory post for CouchRS</font></a><font face="Tahoma">, I explained </font><a href="http://github.com/ashbylane/CouchRS" target="_blank"><font face="Tahoma">where to get the code</font></a><font face="Tahoma"> and how to install the custom processing extension.&#160; Now that you have CouchRS installed, let’s look at a very simple example on how to use it.</font></p>
<p><font face="Tahoma">In Visual Studio 2008, our first step is to create a new Report Server project and add a Shared Data Source to the project, pointing it to our CouchDB server.&#160; The changes we made to our RSReportDesigner.config and RSPreviewPolicy.config (explained in my earlier </font><a href="http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/" target="_blank"><font face="Tahoma">post</font></a><font face="Tahoma">) enable the CouchRS processing extension to be displayed as one of the possible data sources when creating a new data source.&#160; Below is a screen shot of creating this new shared data source:</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/SharedDataSource.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Shared Data Source" border="0" alt="Shared Data Source" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/SharedDataSource_thumb.jpg" width="588" height="435" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">Note that all we have to do is name it, select “CouchDB Connection” from the drop down, and for the connection string we simply provide the server, port and database name.&#160; CouchRS *does* support credentials, but it does <em>not</em> support Integrated Security or Impersonation.&#160; To include credentials with your CouchDB connection, click on the “Credentials” tab, enter a username and password and click OK.</font></p>
<p><font face="Tahoma">With the shared data source now in place, we can create a new (blank) report.&#160; In order for this report to utilize the project-level shared data source, we need to add a report data source as follows (note that you simply select the available shared data source next to the “Use shared data source reference” option):</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/AddReportDataSource.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Add Report Data Source" border="0" alt="Add Report Data Source" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/AddReportDataSource_thumb.jpg" width="574" height="425" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">Now we’re ready to create our first data set, but first we need to discuss “SeeNoSQL”.&#160; “SeeNoSQL” is a very lightweight custom query language that </font><a href="http://digitalbush.com/" target="_blank"><font face="Tahoma">Josh Bush</font></a><font face="Tahoma"> and I created in order to accomplish the following:</font></p>
<ul>
<li><font face="Tahoma">Provide SSRS developers with a readable, “almost-SQL-like-but-not-too-much” way to express queries. </font></li>
<li><font face="Tahoma">Enable complex parameter-driven constraints, including precedence and “AND/OR” chaining within those constraints in order to abstract the need for multiple HTTP requests away from the developer. </font></li>
<li><font face="Tahoma">Provide a concise way to enable users to set more advanced query options, while abstracting the unnecessary elements of it away from the developer. </font></li>
<li><font face="Tahoma">If possible, use the same query syntax against multiple NoSQL storage engines to provide consistency (time will tell on this one as I plan to release custom processing extensions for other NoSQL DBs). </font></li>
</ul>
<p><font face="Tahoma">If you’re even moderately familiar with CouchDB, you know that all interaction with CouchDB is done via HTTP.&#160; Josh and I felt that it would be more intuitive for a developer to write in a declarative style rather than wiring up the raw HTTP requests in the data set’s command text.&#160; So, let’s start with the simplest possible query in “SeeNoSQL”.</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/DataSet1.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="DataSet 1" border="0" alt="DataSet 1" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/DataSet1_thumb.jpg" width="560" height="437" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">In the above screen shot, we’ve named our data set, selected the report data source we created earlier and we’ve entered this command:</font></p>
<p align="center"><font size="2"><font face="Tahoma"><font color="#0000ff">FROM DOCUMENT</font><font color="#000000">(</font><font color="#ff0000"><font color="#000000">&#8216;</font>fff2aaa6-236c-44f2-b2bf-e8a37360768f</font><font color="#000000">&#8216;)</font></font></font></p>
<p><font face="Tahoma">Hopefully, you can infer what’s going on here.&#160; The results being returned will be “FROM” a single “DOCUMENT” with the ID of “fff2aaa6-236c-44f2-b2bf-e8a37360768f”.&#160; It really doesn’t get much simpler than this!&#160; However, this report is <em>not</em> going to be terribly useful if we have the Couch document ID hard coded in our command text.&#160; SeeNoSQL supports parameters, so we can parameterize like this:</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/ParameterizedDataSet.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Parameterized Data Set" border="0" alt="Parameterized Data Set" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/ParameterizedDataSet_thumb.jpg" width="566" height="444" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma">(In future posts, we’ll discuss how to give the user a more meaningful parameter than one that takes an ugly GUID as input!)</font></p>
<p><font face="Tahoma">So – what happens if we click on “Query Designer” and actually run this query?&#160; Here’s the result:</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/QueryDesigner.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="QueryDesigner" border="0" alt="QueryDesigner" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/QueryDesigner_thumb.jpg" width="599" height="453" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">“WAIT A SECOND!”, you say, “I thought we queried for <strong><em>one</em></strong> document!”</font></p>
<p><font face="Tahoma">Yes, we did.&#160; In my </font><a href="http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/" target="_blank"><font face="Tahoma">earlier post</font></a><font face="Tahoma"> I explained that since we’re crawling an object graph, it must be ‘flattened’ into a relational structure (since Reporting Services is using a DataReader under the hood).&#160; And by ‘flattened’ I mean that we have to find the </font><a href="http://en.wikipedia.org/wiki/Cartesian_product" target="_blank"><font face="Tahoma">Cartesian product</font></a><font face="Tahoma"> of each document’s members.&#160; This means if the document has no child collection(s), it’s effectively already flattened.&#160; However, this document has a collection of “SalesOrderHeader” hanging off the root, and each of those items has a collection of “SalesOrderDetails”.&#160; Our example customer has two orders, the first with one line item, and the other with three line items.&#160; The first order and it’s one item can be flattened into <em>one</em> row alongside the Customer information.&#160; The second order has to be flattened into three rows – one for each order detail, alongside the order and customer information – hence the four rows we get back.&#160; The closest analogy to this would be a SQL JOIN causing the results to be “blown out” based on the “many” side of a “one-to-many” relationship.&#160; The implications of this are obvious: To neatly display this data in a report, you need to be mindful of how to properly group it in a Table or List region to avoid unnecessary duplication.&#160; “So”, you ask, “Is there a way to query for only the data I want, rather than getting whole documents back and having to group the records in order to eliminate duplication?”&#160; YES!&#160; You can use a view in CouchDB to customize what is returned so that you only have to deal with the data you want.&#160; I’ll be covering CouchDB views in my next post (this is where “SeeNoSQL” shines, as well).</font></p>
<p><font face="Tahoma">Based on the data returned for this document, I created a simple “Customer Summary” report which displays all of the orders (with detail lines) for a given customer:</font></p>
<p><a href="http://ifandelse.com/img/posts/d2918746c4bb_14B85/CustomerSummarySampleReport.jpg"><font face="Tahoma"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Customer Summary Sample Report" border="0" alt="Customer Summary Sample Report" src="http://ifandelse.com/img/posts/d2918746c4bb_14B85/CustomerSummarySampleReport_thumb.jpg" width="623" height="515" /></font></a><font face="Tahoma"> </font></p>
<p><font face="Tahoma">&#160;</font></p>
<p><font face="Tahoma"></font></p>
<p><font face="Tahoma">It’s worth noting that the images are being dynamically rendered.&#160; In the SQL version of AdventureWorks, these images are stored in varbinary fields, so I included them in my upload to CouchDB.&#160; With the image binary data serialized to JSON, it’s as easy as telling the image control which field to point at for the data, and selecting the MIME type for the image.</font></p>
<p><font face="Tahoma">This is a very simple example, but I hope it helps you appreciate the power of leveraging SSRS against CouchDB.&#160; You can develop the same type of reports using CouchDB as a data source as you can against SQL Server while using a storage medium that’s more friendly to the actual structure of your domain model.</font></p>
<p><font face="Tahoma">We’ve barely scratched the surface….coming up we’ll talk about using map/reduce in CouchDB views, and SeeNoSQL to produce complex requests against CouchDB.</font></p>
<p><em><font size="1" face="Tahoma">[I plan to include the sample reports under the directory structure of my Git repository, but you will not see them in the VS2010 solution, since VS2008 must be used to create these reports as of the time of this post.&#160; Look under the “src'” folder to find this sample project.]</font></em></p>
<img src="http://feeds.feedburner.com/~r/ifandelse/feed/~4/39z8rBL_RTo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://ifandelse.com/2010/07/04/couchrs-building-your-first-report-against-couchdb-using-ssrs/</feedburner:origLink></item>
		<item>
		<title>Introducing CouchRS – an SSRS Processing Extension for CouchDB</title>
		<link>http://feedproxy.google.com/~r/ifandelse/feed/~3/It0G7SNLj8M/</link>
		<comments>http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 05:54:51 +0000</pubDate>
		<dc:creator>Jim Cowart</dc:creator>
				<category><![CDATA[Business Intelligence]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[CouchRS]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[SSRS]]></category>

		<guid isPermaLink="false">http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/</guid>
		<description><![CDATA[Unless you’ve been holed up on a desert island (or perhaps trapped in a legacy .NET 1.0 shop), odds are you have heard of the “NoSQL” movement by now.&#160; Having a background that’s been nearly equally spread across application and database development, I was intrigued when my good friend (and talented developer) Alex Robson first [...]]]></description>
			<content:encoded><![CDATA[<p><font size="2" face="Tahoma">Unless you’ve been holed up on a desert island (or perhaps trapped in a legacy .NET 1.0 shop), odds are you have heard of the “NoSQL” movement by now.&#160; Having a background that’s been nearly equally spread across application and database development, I was intrigued when my good friend (and talented developer) </font><a href="http://sharplearningcurve.com/blog/" target="_blank"><font size="2" face="Tahoma">Alex Robson</font></a><font size="2" face="Tahoma"> first explained CouchDB to me.&#160; I had what are probably the “initial typical” reactions: “Wow, no ORM?&#160; Is it fast?&#160; What about transactions?&#160; Wait, there’s NO schema?&#160; Wow, NO ORM?!”&#160; It was about that time that my data warehousing background piped up and said “Hey, I wonder what kind of analytics we could get out of it?”&#160; As we began to use CouchDB more and more in our applications, we considered approaches that would allow us to leverage our existing BI infrastructure along side of it.&#160; One option – viable, though loaded with more work – was to set up a message bus with listeners that subscribed to commands coming from the UI (or perhaps a ‘trigger’ service monitoring CouchDB for changes).&#160; Those listeners would be responsible for populating a relational (or dimensional) database.&#160; While this is technically viable, it does introduce more potential points for failure, and an overall increase in complexity.&#160; The real world result, then, was we developed our applications against CouchDB, and <em>delayed</em> integrating our BI tools (SSRS, in this case) as long as possible, since we – like most other shops – were pointing SSRS at SQL data stores.</font></p>
<p><font size="2" face="Tahoma">Enter CouchRS.&#160; Several months ago I mentioned to Alex that I wanted to create a </font><a href="http://msdn.microsoft.com/en-us/library/ms152816.aspx" target="_blank"><font size="2" face="Tahoma">Custom Processing Extension</font></a><font size="2" face="Tahoma"> that could allow our reports to simply talk to CouchDB directly.&#160; Easy enough, right?&#160; Well, not so fast.&#160; Remember, CouchDB is a document-oriented database.&#160; It will store anything you throw at it – in the same database.&#160; Want to persist an object graph serialized to JSON?&#160; Done.&#160; Want to save the binary stream of a pdf?&#160; Done.&#160; Feel like storing a recipe list, complete with picture attachments?&#160; Done and done.&#160; With such a wide variance in the type &amp; content of the documents in a Couch database, some general (and powerful) assumptions had to be made.</font></p>
<p><font size="2" face="Tahoma">First – the documents are expected to be JSON.&#160; No big leap there, since that’s standard with Couch.</font></p>
<p><font size="2" face="Tahoma">Second – all the documents in a result set would have to be traversed, and a normalized set of “fields” generated in order to ‘present’ those documents as a relational data set.&#160; Bear in mind that this includes flattening any document that represents an object hierarchy (i.e. – a customer, that has orders, that have order lines, etc.) by producing a Cartesian product of each object graph.&#160; (Alex and </font><a href="http://digitalbush.com/" target="_blank"><font size="2" face="Tahoma">Josh Bush</font></a><font size="2" face="Tahoma"> worked serious magic in this area.&#160; This project would not have been possible without their collaboration.)</font></p>
<p><font size="2" face="Tahoma">Once we were returning results from Couch, Josh and I collaborated on creating a lightweight query syntax (“CouchQuery”) using “</font><a href="http://irony.codeplex.com/" target="_blank"><font size="2" face="Tahoma">Irony</font></a><font size="2" face="Tahoma">” – a fantastic library created by Roman Ivantsov.&#160; It’s SQL-esque enough to be intuitive and readable, without forcing “Couch” into a “SQL” bottle.&#160; I’ll explain more about how to use this syntax in future posts, but suffice it to say that there are exciting implications in that it supports a “UNION” operator, and parenthetical logic (AND, OR, etc.) in the “WHERE” clause, meaning multiple requests can be made against a CouchDB in ONE query, and the results will be returned to the report as if they were one request.&#160; This gets incredibly cool when you start “UNION”-ing the results of different views.</font></p>
<p><font size="2" face="Tahoma">In upcoming posts, I will elaborate more on how to use the query syntax, discuss the necessity of being familiar with Couch views (and map/reduce in general) and present some sample reports.</font></p>
</p>
<p><font size="2" face="Tahoma"></font></p>
<p> <font size="2" face="Tahoma"><strong><em>How do I get it?</em></strong></font>
</p>
<p><font size="2" face="Tahoma">The source is </font><a href="http://github.com/ashbylane/CouchRS" target="_blank"><font size="2" face="Tahoma">located on GitHub</font></a><font size="2" face="Tahoma"> and is available under the Apache 2.0 license (i.e. – it’s yours to download, modify, use in open &amp; closed source applications…so have at it!)</font></p>
<p><font size="2" face="Tahoma"><strong><em>How do I install it?</em></strong></font></p>
<p><font size="2" face="Tahoma">Alas, until I have time to write an installer you must endure this lovely process (it looks worse than what it is, don’t worry):</font></p>
<ul>
<li><font size="2" face="Tahoma">Download the source, build and grab the CouchRS.dll from the bin/Debug or bin/Release </font></li>
<li><font size="2"><font face="Tahoma"><strong>For use with</strong> <strong>Visual Studio 2008 SSRS Designer:</strong> </font></font>
<ul>
<li><font size="2" face="Tahoma">Find your Visual Studio installation folder (usually C:\Program Files\Microsoft Visual Studio 9.0\ or C:\Program Files (x86)\Microsoft Visual Studio 9.0\ on x64 machines).&#160; From there, browse to \Common7\IDE\PrivateAssemblies and paste the CouchRS.dll (along with its dependencies: Irony.dll, Newtonsoft.Json.dll, Symbiote.Core.dll &amp; StructureMap.dll) file into that folder. </font></li>
<li><font size="2" face="Tahoma">In the PrivateAssemblies folder, you need to edit two .config files: RSPreviewPolicy.config and RSReportDesigner.config. </font>
<ul>
<li><font size="2" face="Tahoma"><strong>RSPreviewPolicy.config:</strong></font>
<ul>
<li><font size="2" face="Tahoma">Find the “CodeGroup” element that looks similar to:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                       <br />&lt;</span><span class="html">CodeGroup</span> <span class="attr">class</span><span class="kwrd">=&quot;FirstMatchCodeGroup&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">PermissionSetName</span><span class="kwrd">=&quot;Execution&quot;</span> <span class="attr">Description</span><span class="kwrd">=&quot;This code group grants MyComputer code Execution permission. &quot;</span><span class="kwrd">&gt;                        </p>
<p></span></font></div>
</li>
<li>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd"></span></font><font size="2" face="Tahoma">Find the end of the children of this CodeGroup and paste the following element (be aware that the Url path needs to match where you pasted the CouchRS.dll:</font>                     </p>
<p><font face="Tahoma"><span class="kwrd">&lt;</span><span class="html">CodeGroup</span> <span class="attr">class</span><span class="kwrd">=&quot;UnionCodeGroup&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">PermissionSetName</span><span class="kwrd">=&quot;FullTrust&quot;</span> <span class="attr">Name</span><span class="kwrd">=&quot;CouchDBCodeGroup&quot;</span> <span class="attr">Description</span><span class="kwrd">=&quot;Code group for CouchDB data processing extension&quot;</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;</span><span class="html">IMembershipCondition</span> <span class="attr">class</span><span class="kwrd">=&quot;UrlMembershipCondition&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">Url</span><span class="kwrd">=&quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\                        <br /></span></font><font face="Tahoma"><span class="kwrd">CouchRS.dll&quot;</span><span class="kwrd">/&gt;</span> <span class="kwrd">&lt;/</span><span class="html">CodeGroup</span><span class="kwrd">&gt;</span></font></div>
</li>
</ul>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{<strike></strike>
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</li>
<li><strong><font size="2" face="Tahoma">RSReportDesigner.config:</font></strong>
<ul>
<li><font size="2" face="Tahoma">Find the “Data” element and add a new child element that looks like this:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                       <br />&lt;</span><span class="html">Extension</span> <span class="attr">Name</span><span class="kwrd">=&quot;CouchDB&quot;</span> <span class="attr">Type</span><span class="kwrd">=&quot;CouchRS.DataProcessingExtension.CouchDbConnection                        <br />,CouchRS&quot;</span><span class="kwrd">/&gt;                        </p>
<p></span></font></div>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</li>
<li><font size="2" face="Tahoma">Next, find the “Designer” element and add a new child element that looks like this:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                       <br />&lt;</span><span class="html">Extension</span> <span class="attr">Name</span></font><font face="Tahoma"><span class="kwrd">=&quot;CouchDB&quot;                        <br /></span><span class="attr">Type</span><span class="kwrd">=&quot;Microsoft.ReportingServices.QueryDesigners.GenericQueryDesigner,Microsoft.                        <br />ReportingServices.QueryDesigners&quot;</span><span class="kwrd">/&gt;</span></font></div>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><font size="2"><font face="Tahoma"><strong>For use with a</strong> <strong>SQL Server 2008 Reporting Services Installation</strong>:</font></font>
<ul>
<li><font size="2" face="Tahoma">Find your Report Server’s bin directory (located <em>{SQL Install Directory}\{ReportServer Instance}\Reporting Services\ReportServer\bin</em> – for example: C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\ReportServer\bin) and paste the CouchRS.dll file there (along with its dependencies: Irony.dll, Newtonsoft.Json.dll, Symbiote.Core.dll &amp; StructureMap.dll).</font> </li>
<li><font size="2" face="Tahoma">in the “ReportServer” directory (one level up from the &#8216;”bin”), edit the following files:</font>
<ul>
<li><strong><font size="2" face="Tahoma">rsreportserver.config</font></strong>
<ul>
<li><font size="2" face="Tahoma">Find the Data element and add the following child element:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                       <br />&lt;</span><span class="html">Extension</span> <span class="attr">Name</span><span class="kwrd">=&quot;CouchDB&quot;</span> <span class="attr">Type</span><span class="kwrd">=&quot;CouchRS.DataProcessingExtension.CouchDbConnection                        <br />,CouchRS&quot;</span><span class="kwrd">/&gt;</span></font></div>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</li>
</ul>
</li>
<li><strong><font size="2" face="Tahoma">rssrvpolicy.config</font></strong>
<ul>
<li><font size="2" face="Tahoma">Find the CodeGroup element that looks similar to this:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                       <br />&lt;</span><span class="html">CodeGroup</span> <span class="attr">class</span><span class="kwrd">=&quot;FirstMatchCodeGroup&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">PermissionSetName</span><span class="kwrd">=&quot;Execution&quot;</span> <span class="attr">Description</span><span class="kwrd">=&quot;This code group grants MyComputer code Execution permission. &quot;</span><span class="kwrd">&gt;</span>                       <br /></font></div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<ul>
<ul>
<ul>
<li><font size="2" face="Tahoma">Add a new child element that looks like this:</font>
<div class="csharpcode"><font face="Tahoma"><span class="kwrd">                 <br />&lt;</span><span class="html">CodeGroup</span> <span class="attr">class</span><span class="kwrd">=&quot;UnionCodeGroup&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">PermissionSetName</span><span class="kwrd">=&quot;FullTrust&quot;</span> <span class="attr">Name</span><span class="kwrd">=&quot;CouchDBCodeGroup&quot;</span> <span class="attr">Description</span><span class="kwrd">=&quot;Code group for CouchDB data processing extension&quot;</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;</span><span class="html">IMembershipCondition</span> <span class="attr">class</span><span class="kwrd">=&quot;UrlMembershipCondition&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">Url</span><span class="kwrd">=&quot;C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\                  <br />Reporting Services\ReportServer\bin\CouchRS.dll&quot;</span> <span class="kwrd">/&gt;</span> <span class="kwrd">&lt;</span><span class="html">IPermission</span> <span class="attr">class</span><span class="kwrd">=&quot;SecurityPermission&quot;</span> <span class="attr">version</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">Flags</span><span class="kwrd">=&quot;Execution&quot;</span><span class="kwrd">/&gt;</span> <span class="kwrd">&lt;/</span><span class="html">CodeGroup</span><span class="kwrd">&gt;</span></font></div>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</li>
</ul>
</ul>
<li><font size="2"><font face="Tahoma">You should recycle the SSRS Service at this point.<br />
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p></font></font> </li>
</ul>
</ul>
<p>There is more to come!&#160; If your interest is piqued, please leave a comment, Retweet this post and watch our repository on GitHub…</p>
<p> <font size="2" face="Tahoma">
<p></p>
<p> </font>
<p><font size="2" face="Tahoma"></font></p>
<img src="http://feeds.feedburner.com/~r/ifandelse/feed/~4/It0G7SNLj8M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://ifandelse.com/2010/06/30/introducing-couchrs-an-ssrs-processing-extension-for-couchdb/</feedburner:origLink></item>
	</channel>
</rss>
