Facebook's FQL Multi-Query


Introduction

At work, my team is currently developing a social media management application. I am focused now on displaying some data charts and tables. All of the code is client-side JavaScript. To populate the charts, we make calls to Facebook.

Facebook has a SQL like query language, FQL,  which allows you to request various data points about your pages, applications, etc. When you need a single data point like your page's total fans, you make a call to the method, fql.query to get your data. For a single data point this is great, but what if you are building a chart and need more than one data point? Making repeated calls to Facebook, will quickly begin to become tedious and slow. Luckily, Facebook has another method, fql.multi-query, which allows you to submit multiple queries at the same time and receive them back in a single result-set.

Submitting Data
Submitting queries to multi-query is only slightly more complicated than doing a single query. A single query request looks like:

var query = “SELECT metric, value FROM insights WHERE object_id=162705687107157 AND metric='page_fans' AND end_time=end_time_date('2011-04-01') AND period=period('lifetime')”;

FB.api({ access_token:accessToken, method: 'fql.query', query: query }, function (data) { // do something });

A multi-query request looks like:

var queries = {
d20110401:“SELECT metric, value FROM insights WHERE object_id=162705687107157 AND metric='page_fans' AND end_time=end_time_date('2011-04-01') AND period=period('lifetime')”,
d20110404:"SELECT metric, value FROM insights WHERE object_id=162705687107157 AND metric='page_fans' AND end_time=end_time_date('2011-04-04') AND period=period('lifetime')",
d20110407:"SELECT metric, value FROM insights WHERE object_id=162705687107157 AND metric='page_fans' AND end_time=end_time_date('2011-04-07') AND period=period('lifetime')",
d20110410:"SELECT metric, value FROM insights WHERE object_id=162705687107157 AND metric='page_fans' AND end_time=end_time_date('2011-04-10') AND period=period('lifetime')"}

FB.api({ access_token:accessToken, method: 'fql.multiquery', queries: queries }, function (data) { // do something });

The only things that change are the name of the method from fql.query to fql.multiquery and instead of query, we now have queries. Please note: queries is a property and not an array. A property in JavaScript is like a dictionary in other languages. So each entry is a key/value pair. The key of each query is used to identify its data in the result-set.

Retrieving Data
One challenge of using multi-query is in changing the returned result-set into more easily used data. Here is what the result-set looks like for the preceding queries::

resultset = {
[ { "fql_result_set" : [ { "metric" : "page_fans", "value" : "31" } ],
   "name" : "d20110401"
 },
 { "fql_result_set" : [ { "metric" : "page_fans", "value" : "31" } ],
   "name" : "d20110404"
 },
 { "fql_result_set" : [ { "metric" : "page_fans", "value" : "31" } ],
   "name" : "d20110407"
 },
 { "fql_result_set" : [ { "metric" : "page_fans", "value" : "31" } ],
   "name" : "d20110410"
 }
]};


The resultset neatly encapsulates all of the information asked for by the query. Please note: the keys of the request are now identified by the name keys of each fql_result_set. Unfortunately, this data is a bit cumbersome to work with. For displaying charts an array is much easier to use. So I wrote the following general purpose method to change the result-set into an array.

FilterData: function (data, processedData, criteria, name) {
 var prop, ptr, type;
 for (prop in data) {
   ptr = data[prop];
   type = typeof (ptr);
   if (type === "object") {
     // is this the field holding the desired data?
     if (ptr && ptr.metric && ptr.metric === criteria) {
       processedData.push({ metric: ptr.metric, value: ptr.value, name: name });
     } else {
       // search deeper into the object
       this.FilterData(ptr, processedData, criteria, name);
     }
   } else if (type === "string" && prop === "name") {
     // save the name of the current query
     name = ptr;
   }
 }
}


The FilterData method uses recursion to search through the JavaScript property, data. Each time it finds a match to criteria, it pushes a new value onto the array, processedData. The value pushed onto the array is a property consisting of: the name of the query, the name of the metric, and the value of the metric. This design allows the method to be able to search through result-sets which have more than one metric returned.

Summary
It is always a best practice to minimize the number of out of process calls your application makes. Facebook’s multi-query makes it easy to get all of the data you need in one call.

Popular Posts