I'm trying to create a timeseries chart with several series, using a dataset that comes from an api in the following format:
dataset: {
dimensions: ['tstamp', 'prod'],
source: [
{ src:1, tstamp: '2021-09-16T16:40:30Z', prod: 1 },
{ src:1, tstamp: '2021-09-16T16:41:25Z', prod: 2 },
{ src:1, tstamp: '2021-09-16T16:42:26Z', prod: 3 },
{ src:1, tstamp: '2021-09-16T16:43:32Z', prod: 4 },
{ src:1, tstamp: '2021-09-16T16:44:24Z', prod: 5 },
{ src:1, tstamp: '2021-09-16T16:45:26Z', prod: 6 },
{ src:1, tstamp: '2021-09-16T16:46:30Z', prod: 7 },
{ src:1, tstamp: '2021-09-16T16:47:32Z', prod: 8 },
{ src:1, tstamp: '2021-09-16T16:48:31Z', prod: 9 },
{ src:1, tstamp: '2021-09-16T16:49:28Z', prod: 10 },
{ src:2, tstamp: '2021-09-16T16:40:12Z', prod: 1 },
{ src:2, tstamp: '2021-09-16T16:41:18Z', prod: 2 },
{ src:2, tstamp: '2021-09-16T16:42:09Z', prod: 3 },
{ src:2, tstamp: '2021-09-16T16:43:11Z', prod: 4 },
{ src:2, tstamp: '2021-09-16T16:44:17Z', prod: 5 },
{ src:2, tstamp: '2021-09-16T16:45:02Z', prod: 6 },
{ src:2, tstamp: '2021-09-16T16:46:06Z', prod: 7 },
{ src:2, tstamp: '2021-09-16T16:47:11Z', prod: 8 },
{ src:2, tstamp: '2021-09-16T16:48:14Z', prod: 9 },
{ src:2, tstamp: '2021-09-16T16:49:10Z', prod: 10 },
]
}
x comes from "tstamp", and y comes from "prod", but I don't know how use the "src" field to separate two series. Note that I can't organize the data as having { tstamp, prod1, prod2 } since the timestamps are not synchronized.
Is it possible to do this?
Thanks!
Generally, you need to construct 2 lists for each src
Copy-paste the following code in the Echarts-code-editor website to validate the result.
let dataset = {
dimensions: ['tstamp', 'prod'],
source: [
{ src: 1, tstamp: '2021-09-16T16:40:30Z', prod: 1 },
{ src: 1, tstamp: '2021-09-16T16:41:25Z', prod: 2 },
{ src: 1, tstamp: '2021-09-16T16:42:26Z', prod: 3 },
{ src: 1, tstamp: '2021-09-16T16:43:32Z', prod: 4 },
{ src: 1, tstamp: '2021-09-16T16:44:24Z', prod: 5 },
{ src: 1, tstamp: '2021-09-16T16:45:26Z', prod: 6 },
{ src: 1, tstamp: '2021-09-16T16:46:30Z', prod: 7 },
{ src: 1, tstamp: '2021-09-16T16:47:32Z', prod: 8 },
{ src: 1, tstamp: '2021-09-16T16:48:31Z', prod: 9 },
{ src: 1, tstamp: '2021-09-16T16:49:28Z', prod: 10 },
{ src: 2, tstamp: '2021-09-16T16:40:12Z', prod: 1 },
{ src: 2, tstamp: '2021-09-16T16:41:18Z', prod: 5 },
{ src: 2, tstamp: '2021-09-16T16:42:09Z', prod: 4 },
{ src: 2, tstamp: '2021-09-16T16:43:11Z', prod: 4 },
{ src: 2, tstamp: '2021-09-16T16:44:17Z', prod: 7 },
{ src: 2, tstamp: '2021-09-16T16:45:02Z', prod: 9 },
{ src: 2, tstamp: '2021-09-16T16:46:06Z', prod: 0 },
{ src: 2, tstamp: '2021-09-16T16:47:11Z', prod: 3 },
{ src: 2, tstamp: '2021-09-16T16:48:14Z', prod: 2 },
{ src: 2, tstamp: '2021-09-16T16:49:10Z', prod: 1 }
]
};
// getting unique srcs for manipulting
const uniqueSrc = Array.from(new Set(dataset.source.map((item) => item.src)));
// getting chart labels
const chartLabels = dataset.source.map((row) => row.tstamp);
// getting lists of data filtered by src
const chartData = uniqueSrc.map((uniqueSrc) => {
return {
label: uniqueSrc,
data: dataset.source.map((obj) => {
if (obj.src == uniqueSrc) {
return obj.prod;
} else {
return 0;
}
}),
};
});
option = {
title: {
text: 'Stacked Line'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: uniqueSrc.map((item) => item.toString()) // modifier legends
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: chartLabels // modified chart labels
},
yAxis: {
type: 'value'
},
// modified series
series: chartData.map((obj, index) => {
return {
name: obj.label,
type: 'line',
data: obj.data
};
})
};
Related
I have looked over the documentation but it not works.
const editorInstance = CodeMirror.fromTextArea(editor.value, {})
editorInstance.markText(
{ line: 1, ch: 1 },
{ line: 1, ch: 10 },
{ readOnly: true,}
);
I'm trying to make an horizontal histogram with y labels on top of each bar with the really nice libray echarts. Here is an example:
Here is where I am with this jsfiddle https://jsfiddle.net/795f84o0/6/ :
Echarts documentation is really good but I did not found a way to put these labels (sankey, funnel, gauge....) on top on each bar :/
Do you have any idea how I can do it? Thank you for your help!
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
var builderJson = {
"all": 10887,
"charts": {
"map": 3237,
"lines": 2164,
"bar": 7561,
"line": 7778,
"pie": 7355,
"scatter": 2405,
"candlestick": 1842,
"radar": 2090,
"heatmap": 1762,
"treemap": 1593,
"graph": 2060,
"boxplot": 1537,
"parallel": 1908,
"gauge": 2107,
"funnel": 1692,
"sankey": 1568
},
"components": {
"geo": 2788,
"title": 9575,
"legend": 9400,
"tooltip": 9466,
"grid": 9266,
"markPoint": 3419,
"markLine": 2984,
"timeline": 2739,
"dataZoom": 2744,
"visualMap": 2466,
"toolbox": 3034,
"polar": 1945
},
"ie": 9743
};
option = {
xAxis: [{
type: 'value',
max: builderJson.all,
}],
yAxis: [{
data: Object.keys(builderJson.charts),
axisLabel: {
show: false,
},
},
{
data: Object.keys(builderJson.charts),
axisLabel: {
show: true,
},
},
],
series: [{
type: 'bar',
data: Object.keys(builderJson.charts).map(function (key) {
return builderJson.charts[key];
})
}]
};
option && myChart.setOption(option);
All right, I got it after two hours...
Just posting a screenshot to show the result:
The fiddle and the code :
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
var builderJson = {
"all": 100,
"charts": {
"pie": 1,
"scatter": 1,
"candlestick": 1,
"radar": 2,
"heatmap": 3,
"treemap": 6,
"graph": 7,
"boxplot": 7,
"parallel": 8,
"gauge": 9,
"funnel": 15,
"sankey": 30
},
};
option = {
xAxis: [{
type: 'value',
max: builderJson.all,
axisLabel: {
show: false,
},
splitLine: {
show: false
}
},
],
yAxis: [{
data: Object.keys(builderJson.charts),
axisLabel: {
show: false,
},
splitLine: {
show: false
},
axisLine: {
show: false
},
axisTick: {
show: false,
}
},
],
series: [{
type: 'bar',
stack: 'chart',
barCategoryGap: 30,
barWidth: 20,
label: {
position: [0, -14],
formatter: '{b}',
show: true
},
itemStyle: {
borderRadius: [0, 2, 2, 0],
},
data: Object.keys(builderJson.charts).map(function (key) {
return builderJson.charts[key];
})
},
{
type: 'bar',
stack: 'chart',
barCategoryGap: 30,
barWidth: 20,
itemStyle: {
color: 'whitesmoke'
},
label: {
position: 'insideRight',
formatter: function(params) { return 100 - params.value + '%'},
show: true
},
data: Object.keys(builderJson.charts).map(function (key) {
return builderJson.all - builderJson.charts[key];
})
}
]
};
option && myChart.setOption(option);
I am at a loss on why Google column chart is repeating the x-axis label.
Please find the CodePen URL: https://codepen.io/anon/pen/MPOJQG?editors=0010
You may notice that I have tried both the approaches:
arrayToDataTable (line #4 in code pen)
conventional datatable structure (line #5 in code pen)
Following is the code from CodePen link:
//console.log("Loading current Google charts");
google.charts.load("current");
google.charts.setOnLoadCallback(function() {
//let dataTable = new google.visualization.arrayToDataTable(GetJSONArray()); //This also has the same issue
let dataTable = new google.visualization.DataTable(GetJSONData());
RenderChart(dataTable, "chart");
});
function RenderChart(dataTable, elementId) {
try {
const dateFormat = "MMM dd";
//debugger;
let numberOfRows = dataTable.getNumberOfRows();
let options = {
tooltip: { isHtml: true /*, trigger: 'selection'*/ },
height: 240,
legend: { position: "bottom" },
colors: ["#4CAF50"],
chartArea: { left: 80, top: 20, width: "90%" },
//isStacked: 'true',
hAxis: {
format: dateFormat
//gridlines: { count: numberOfRows }
},
vAxis: {
//format: '%',
title: "Percentage",
viewWindow: {
max: 100,
min: 0
}
}
};
if (numberOfRows === 1) {
//If there is only one date then Google chart messes up the chart, in that case it is must to set viewWindow
let hAxis = {
hAxis: {
viewWindow: {
min: dataTable.getValue(0, 0),
max: dataTable.getValue(numberOfRows - 1, 0)
}
}
};
options = $.extend(true, options, hAxis);
}
let wrapper = new google.visualization.ChartWrapper({
chartType: "ColumnChart",
dataTable: dataTable,
options: options,
containerId: elementId
});
wrapper.draw();
} catch (e) {
console.log(e.toString());
}
}
function GetJSONArray(){
let data = [
['Date', 'Pass', { role: 'annotation' } , {'type': 'string', 'role': 'tooltip', 'p': {'html': true}} ],
[new Date(2018, 9, 6),96, "48 (96.00%)", "<div>2018-10-06 (Sat)</div><div> - Pass: 48 (96.00%)</div><div> - Fail: 2 (4.00%)</div>"],
[new Date(2018, 9, 8),96.55172413793103448275862069,"168 (96.55%)","<div>2018-10-08 (Mon)</div><div> - Pass: 168 (96.55%)</div><div> - Fail: 6 (3.45%)</div>"],
[new Date(2018, 9, 9),95.82409460458240946045824095,"2,593 (95.82%)","<div>2018-10-09 (Tue)</div><div> - Pass: 2,593 (95.82%)</div><div> - Fail: 113 (4.18%)</div>"],
[new Date(2018, 9, 10),96.81303116147308781869688385,"2,734 (96.81%)","<div>2018-10-10 (Wed)</div><div> - Pass: 2,734 (96.81%)</div><div> - Fail: 90 (3.19%)</div>"],
[new Date(2018, 9, 11),96.80555555555555555555555556,"2,788 (96.81%)","<div>2018-10-11 (Thu)</div><div> - Pass: 2,788 (96.81%)</div><div> - Fail: 92 (3.19%)</div>"],
[new Date(2018, 9, 12),96.863295880149812734082397,"2,069 (96.86%)","<div>2018-10-12 (Fri)</div><div> - Pass: 2,069 (96.86%)</div><div> - Fail: 67 (3.14%)</div>"]
]
return data;
}
function GetJSONData() {
return {
cols: [
{ type: "date", id: "Date", label: "Date" },
{ type: "number", id: "Pass", label: "Pass %" },
{
type: "string",
id: "Annotation",
label: "Annotation",
p: { role: "annotation" }
},
{
type: "string",
id: "ToolTip",
label: "ToolTip",
p: { html: "true", role: "tooltip" }
}
],
rows: [
{
c: [
{ v: "Date(2018, 9, 6)" },
{ v: 96 },
{ v: "48 (96.00%)" },
{
v:
"<div>2018-10-06 (Sat)</div><div> - Pass: 48 (96.00%)</div><div> - Fail: 2 (4.00%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 8)" },
{ v: 96.55172413793103448275862069 },
{ v: "168 (96.55%)" },
{
v:
"<div>2018-10-08 (Mon)</div><div> - Pass: 168 (96.55%)</div><div> - Fail: 6 (3.45%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 9)" },
{ v: 95.82409460458240946045824095 },
{ v: "2,593 (95.82%)" },
{
v:
"<div>2018-10-09 (Tue)</div><div> - Pass: 2,593 (95.82%)</div><div> - Fail: 113 (4.18%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 10)" },
{ v: 96.81303116147308781869688385 },
{ v: "2,734 (96.81%)" },
{
v:
"<div>2018-10-10 (Wed)</div><div> - Pass: 2,734 (96.81%)</div><div> - Fail: 90 (3.19%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 11)" },
{ v: 96.80555555555555555555555556 },
{ v: "2,788 (96.81%)" },
{
v:
"<div>2018-10-11 (Thu)</div><div> - Pass: 2,788 (96.81%)</div><div> - Fail: 92 (3.19%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 12)" },
{ v: 96.863295880149812734082397 },
{ v: "2,069 (96.86%)" },
{
v:
"<div>2018-10-12 (Fri)</div><div> - Pass: 2,069 (96.86%)</div><div> - Fail: 67 (3.14%)</div>"
}
]
}
]
};
}
I have also referred following URLs:
Duplicate label on x-axis, stacking bar chart (google charts)
since you're using datetime for x-axis,
the chart doesn't know it should only show one label for each day.
instead, it adds dates to fill the range of the x-axis.
and since the format does not include time,
labels are repeated.
to correct, use option hAxis.ticks to provide your own labels.
to build dynamically, use data table method --> getColumnRange
this will return the min and max dates in the table.
then build an array of dates for each day.
let dateRange = dataTable.getColumnRange(0);
for (var i = dateRange.min.getTime(); i <= dateRange.max.getTime(); i = i + oneDay) {
hAxisTicks.push(new Date(i));
}
see following working snippet...
google.charts.load("current");
google.charts.setOnLoadCallback(function() {
//let dataTable = new google.visualization.arrayToDataTable(GetJSONArray()); //This also has the same issue
let dataTable = new google.visualization.DataTable(GetJSONData());
RenderChart(dataTable, "chart");
});
function RenderChart(dataTable, elementId) {
try {
const dateFormat = "MMM dd";
const oneDay = (1000 * 60 * 60 * 24);
//debugger;
let hAxisTicks = [];
let dateRange = dataTable.getColumnRange(0);
for (var i = dateRange.min.getTime(); i <= dateRange.max.getTime(); i = i + oneDay) {
hAxisTicks.push(new Date(i));
}
let numberOfRows = dataTable.getNumberOfRows();
let options = {
tooltip: { isHtml: true /*, trigger: 'selection'*/ },
height: 240,
legend: { position: "bottom" },
colors: ["#4CAF50"],
chartArea: { left: 80, top: 20, width: "90%" },
//isStacked: 'true',
hAxis: {
format: dateFormat,
ticks: hAxisTicks
//gridlines: { count: numberOfRows }
},
vAxis: {
//format: '%',
title: "Percentage",
viewWindow: {
max: 100,
min: 0
}
}
};
if (numberOfRows === 1) {
//If there is only one date then Google chart messes up the chart, in that case it is must to set viewWindow
let hAxis = {
hAxis: {
viewWindow: {
min: dataTable.getValue(0, 0),
max: dataTable.getValue(numberOfRows - 1, 0)
}
}
};
options = $.extend(true, options, hAxis);
}
let wrapper = new google.visualization.ChartWrapper({
chartType: "ColumnChart",
dataTable: dataTable,
options: options,
containerId: elementId
});
wrapper.draw();
} catch (e) {
console.log(e.toString());
}
}
function GetJSONArray(){
let data = [
['Date', 'Pass', { role: 'annotation' } , {'type': 'string', 'role': 'tooltip', 'p': {'html': true}} ],
[new Date(2018, 9, 6),96, "48 (96.00%)", "<div>2018-10-06 (Sat)</div><div> - Pass: 48 (96.00%)</div><div> - Fail: 2 (4.00%)</div>"],
[new Date(2018, 9, 8),96.55172413793103448275862069,"168 (96.55%)","<div>2018-10-08 (Mon)</div><div> - Pass: 168 (96.55%)</div><div> - Fail: 6 (3.45%)</div>"],
[new Date(2018, 9, 9),95.82409460458240946045824095,"2,593 (95.82%)","<div>2018-10-09 (Tue)</div><div> - Pass: 2,593 (95.82%)</div><div> - Fail: 113 (4.18%)</div>"],
[new Date(2018, 9, 10),96.81303116147308781869688385,"2,734 (96.81%)","<div>2018-10-10 (Wed)</div><div> - Pass: 2,734 (96.81%)</div><div> - Fail: 90 (3.19%)</div>"],
[new Date(2018, 9, 11),96.80555555555555555555555556,"2,788 (96.81%)","<div>2018-10-11 (Thu)</div><div> - Pass: 2,788 (96.81%)</div><div> - Fail: 92 (3.19%)</div>"],
[new Date(2018, 9, 12),96.863295880149812734082397,"2,069 (96.86%)","<div>2018-10-12 (Fri)</div><div> - Pass: 2,069 (96.86%)</div><div> - Fail: 67 (3.14%)</div>"]
]
return data;
}
function GetJSONData() {
return {
cols: [
{ type: "date", id: "Date", label: "Date" },
{ type: "number", id: "Pass", label: "Pass %" },
{
type: "string",
id: "Annotation",
label: "Annotation",
p: { role: "annotation" }
},
{
type: "string",
id: "ToolTip",
label: "ToolTip",
p: { html: "true", role: "tooltip" }
}
],
rows: [
{
c: [
{ v: "Date(2018, 9, 6)" },
{ v: 96 },
{ v: "48 (96.00%)" },
{
v:
"<div>2018-10-06 (Sat)</div><div> - Pass: 48 (96.00%)</div><div> - Fail: 2 (4.00%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 8)" },
{ v: 96.55172413793103448275862069 },
{ v: "168 (96.55%)" },
{
v:
"<div>2018-10-08 (Mon)</div><div> - Pass: 168 (96.55%)</div><div> - Fail: 6 (3.45%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 9)" },
{ v: 95.82409460458240946045824095 },
{ v: "2,593 (95.82%)" },
{
v:
"<div>2018-10-09 (Tue)</div><div> - Pass: 2,593 (95.82%)</div><div> - Fail: 113 (4.18%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 10)" },
{ v: 96.81303116147308781869688385 },
{ v: "2,734 (96.81%)" },
{
v:
"<div>2018-10-10 (Wed)</div><div> - Pass: 2,734 (96.81%)</div><div> - Fail: 90 (3.19%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 11)" },
{ v: 96.80555555555555555555555556 },
{ v: "2,788 (96.81%)" },
{
v:
"<div>2018-10-11 (Thu)</div><div> - Pass: 2,788 (96.81%)</div><div> - Fail: 92 (3.19%)</div>"
}
]
},
{
c: [
{ v: "Date(2018, 9, 12)" },
{ v: 96.863295880149812734082397 },
{ v: "2,069 (96.86%)" },
{
v:
"<div>2018-10-12 (Fri)</div><div> - Pass: 2,069 (96.86%)</div><div> - Fail: 67 (3.14%)</div>"
}
]
}
]
};
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>
Series is one document. It has an array of series inside it (in this case it has 'Revenge' and 'Raines').
Each series has a cast array with names. And I need a query to get those names.
Who know how can I get a list of all the names from both cast arrays?
My best approach was this query db.series.find( {}, { _id: 0, cast: 1 } ) where a get a cursor with the two cast json arrays.
{ series:
[
{
name: 'Revenge',
user_rating: 7.9,
duration: 44,
genres: [ ' Drama', ' Mystery', ' Thriller' ],
year_start: '2011',
year_end: '',
cast:
[ { name: 'Madeleine Stowe' },
{ name: 'Emily VanCamp' },
{ name: 'Gabriel Mann' },
{ name: 'Nick Wechsler' },
{ name: 'Henry Czerny' },
{ name: 'Joshua Bowman' },
{ name: 'Christa B. Allen' },
{ name: 'Ashley Madekwe' },
{ name: 'Connor Paolo' },
{ name: 'Barry Sloane' },
{ name: 'Margarita Levieva' } ],
seasons: [ { number: '3' }, { number: '2' }, { number: '1' } ]
},
{
name: 'Raines',
user_rating: 7.4,
duration: 45,
genres: [ ' Crime', ' Drama' ],
year_start: '2007',
year_end: '',
cast:
[ { name: 'Jeff Goldblum' },
{ name: 'Matt Craven' },
{ name: 'Nicole Sullivan' },
{ name: 'Linda Park' },
{ name: 'Dov Davidoff' },
{ name: 'Malik Yoba' },
{ name: 'Madeleine Stowe' } ],
seasons: [ { number: '1' } ]
}
]
}
I need an output like this:
I need this:
{ name: 'Madeleine Stowe' },
{ name: 'Emily VanCamp' },
{ name: 'Gabriel Mann' },
{ name: 'Nick Wechsler' },
{ name: 'Henry Czerny' },
{ name: 'Joshua Bowman' },
{ name: 'Christa B. Allen' },
{ name: 'Ashley Madekwe' },
{ name: 'Connor Paolo' },
{ name: 'Barry Sloane' },
{ name: 'Margarita Levieva' },
{ name: 'Jeff Goldblum' },
{ name: 'Matt Craven' },
{ name: 'Nicole Sullivan' },
{ name: 'Linda Park' },
{ name: 'Dov Davidoff' },
{ name: 'Malik Yoba' },
{ name: 'Madeleine Stowe' }
You can use aggregation framework for this:
db.series.aggregate( { $unwind : "$series" },
{ $unwind : "$series.cast" },
{ $group : { _id : "$_id",
cast : {$push:"$series.cast}
}
}
);
If you want to consolidate multiple actor appearances into one then replace $push with $addToSet.
With the following schema (defined below). I can use map reduce to aggregate the delivered_count field for all days (which is an embedded array inside the campaign document).
{
campaign_id: 1,
status: 'running',
dates: {
'20130926' => {
delivered: 1,
failed: 1,
queued: 1,
clicked: 1,
males_count: 1,
females_count: 1,
pacific_region: { clicked_count: 10 },
america_region: { clicked_count: 10 },
atlantic_region: { clicked_count: 10 },
europe_region: { clicked_count: 10 },
africa_region: { clicked_count: 10 },
etc_region: { clicked_count: 10 },
asia_region: { clicked_count: 10 },
australia_region: { clicked_count: 10 }
},
'20130927' => {
delivered: 1,
failed: 1,
queued: 1,
clicked: 1,
males_count: 1,
females_count: 1,
pacific_region: { clicked_count: 10 },
america_region: { clicked_count: 10 },
atlantic_region: { clicked_count: 10 },
europe_region: { clicked_count: 10 },
africa_region: { clicked_count: 10 },
etc_region: { clicked_count: 10 },
asia_region: { clicked_count: 10 },
australia_region: { clicked_count: 10 }
},
'20130928' => {
delivered: 1,
failed: 1,
queued: 1,
clicked: 1,
males_count: 1,
females_count: 1,
pacific_region: { clicked_count: 10 },
america_region: { clicked_count: 10 },
atlantic_region: { clicked_count: 10 },
europe_region: { clicked_count: 10 },
africa_region: { clicked_count: 10 },
etc_region: { clicked_count: 10 },
asia_region: { clicked_count: 10 },
australia_region: { clicked_count: 10 }
}
}
}
The code below parses through field asia_regions outputs the value of field clicked_count => 30 (combined value of all data)
$rethinkdb.table(:daily_stat_campaigns).filter { |daily_stat_campaign| daily_stat_campaign[:campaign_id].eq 1 }[0][:dates].do { |doc|
doc.keys.map { |key|
doc.get_field(key)[:asia_region][:clicked_count].default(0)
}.reduce { |left, right|
left+right
}
}.run
Is it possible to run the code above but against multiple regions? This way I can run one query which will return multiple sums. The output i'm trying to achieve is something similar to the pseudo result below.
[{ asia_region: {clicked_count: 30}}, {america_region: {clicked_count: 30} }]
This seems to work:
require 'awesome_print' # For better readability on output
regions = [:pacific_region, :america_region]
reg_clicks = $rethinkdb.table(:daily_stat_campaigns).filter { |daily_stat_campaign| daily_stat_campaign[:campaign_id].eq 1 }[0][:dates].do { |doc|
doc.keys.concat_map { |key|
doc
.get_field(key)
.pluck(regions)
.coerce_to("ARRAY")
}
}
ap reg_clicks.run
Will output something like: [["america_region", {"clicked_count"=>10}], ["pacific_region", {"clicked_count"=>10}], ["america_region", {"clicked_count"=>10}], ["pacific_region", {"clicked_count"=>10}], ["america_region", {"clicked_count"=>10}], ["pacific_region", {"clicked_count"=>10}]]
aggregate = reg_clicks.map { |reg|
{ reg: reg[0], clicked_count: reg[1][:clicked_count] }
}
ap aggregate.run
Will output: [{"reg"=>"america_region", "clicked_count"=>10}, {"reg"=>"pacific_region", "clicked_count"=>10}, {"reg"=>"america_region", "clicked_count"=>10}, {"reg"=>"pacific_region", "clicked_count"=>10}, {"reg"=>"america_region", "clicked_count"=>10}, {"reg"=>"pacific_region", "clicked_count"=>10}]
ap aggregate.group_by(:reg, $rethinkdb_rql.sum(:clicked_count)).run
Outputs: [{"reduction"=>30, "group"=>{"reg"=>"america_region"}}, {"reduction"=>30, "group"=>{"reg"=>"pacific_region"}}]
I'm a bit confused about the code that you posted. Why is everything inside of a filter? To output something like what you want do the following:
regions = [:pacific_region, :america_region, ...]
reg_clicks = r.table(:daily_stat_campaigns).concat_map { |row|
row[:dates]
.coerce_to("ARRAY")
.map{ |date| date[0] }
.pluck(regions)
.coerce_to("ARRAY")
}
You can now run reg_clicks and it should look something like this:
$ reg_clicks.run()
[[:asia_region, {clicked_count: 30}], [:etc_region, {clicked_count: 30}], ...]
Now we need to do one last transformation to aggregate it:
$ aggregate = reg_clicks.map{ |reg|
{reg: reg[0], clicked_count: reg[0][:clicked_count]}
}
.group_by(:reg, r.sum(:clicked_count))
this will give you output that looks like:
[{group: :asia_region, reduction: 150} ...]
if you want it too look exactly like what you want then you can apply a final transformation:
aggregate.map{ |row|
[row[:group], row[:reduction]]
}
.coerce_to("OBJECT")
These queries would definitely be a bit nicer if you normalized the data a bit. Breaking things out into a 2 more tables called :dates and :region_clicks that looked like so:
#dates
{
id: 0
campaign_id: 1
date: '20130927'
delivered: 1,
failed: 1,
queued: 1,
clicked: 1,
males_count: 1
}
#region_clicks
{
region: "asia_region",
click_count: 30,
date_id: 0
}
Then your query would be as simple as:
r.table(:region_clicks).group_by(:region, r.sum(:click_count)).run()