如何制作一个通用函数来将嵌套对象缩减为 CSV 样式数组?
How can I make a generic function to reduce a nested object into a CSV style array?
我正在尝试弄清楚如何将嵌套的 array/tree 扁平化为 CSV 样式格式。
我有一个来自 elasticsearch 的结果,如下所示(注意 - 每个 'buckets' 属性 可以有多个或 0 个项目):
$data = array(
'reeta.datetime_day' => array(
'buckets' => array(
0 => array(
'key_as_string' => '2018-07-27T00:00:00.000Z',
'key' => 1532649600000,
'doc_count' => 4,
'ticket.employee_name' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Era Swift',
'doc_count' => 3,
'ticket.order_type' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Dine In',
'doc_count' => 3,
'ticket.total_guest_count' => array(
'value' => 17,
) ,
'ticket.total_revenue' => array(
'value' => 273,
) ,
) ,
) ,
) ,
) ,
1 => array(
'key' => 'Dorothea Friesen',
'doc_count' => 1,
'ticket.order_type' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Take Out',
'doc_count' => 1,
'ticket.total_guest_count' => array(
'value' => 2,
) ,
'ticket.total_revenue' => array(
'value' => 195,
) ,
) ,
) ,
) ,
) ,
) ,
) ,
)
)
)
);
我有一个用于获取这些聚合的维度和指标列表,它们各不相同,例如,上面的结果使用以下内容:
$dimensions = ['reeta.datetime_day', 'ticket.employee_name', 'ticket.order_type'];
$metrics = ['ticket.total_guest_count', 'ticket.total_revenue'];
我希望是这样的:
$result = [
// the first bucket of the deepest dimension (ticket.order_type)
[
1532649600000, // the first dimensions key value
'Era Swift', // the second dimensions key value
'Dine In', // the thirs dimensions key value
17, // the first metrics value
273 // the second metrics value
],
// the second bucket of the deepest dimension (ticket.order_type)
[
1532649600000, // the first dimensions key value
'Dorothea Friesen', // the second dimensions key value
'Take Out', // the thirs dimensions key value
2, // the first metrics value
195 // the second metrics value
],
];
为了更好地解释我的用例,我创建了一个 API,它接受许多维度和指标,然后查询 ES 以获得结果。然后,我将获取这些结果并使用它们为 Google 图表 (https://developers.google.com/chart/interactive/docs/datatables_dataviews).
创建数据表
我尝试编写许多递归函数,array_walk_recursive 等,并尝试使用谷歌搜索任何类似的示例,但找不到任何地方。
我尝试遍历并检查:
$array[$dimension]['buckets']
要知道当索引不存在时我处于最深层次
但我总是得到不正确的结果。我只是无法简单地展平数组,因为我需要为每个最深层次的桶提供一个数组项。
希望这能说得通,但我很乐意在这里澄清并提供更大的数据集:
https://pastebin.com/mU2xkQGB
如果有人能指出我正确的方向或任何类似的示例,我将不胜感激,我确实有一堆嵌套的 foreach 块在某个时候工作,但一旦我改变维度的数量当然没用。
我确实设法找到了一种解决方案,它绝对不是最好的,但它通常适用于任意数量的维度和指标。
本质上,我使用 https://github.com/nicmart/Tree 构建了一个树对象,因此可以遍历节点,但是我想要,所以每次我必须添加指标时,我都可以遍历回到它的父节点并创建一个 table 行。
查看下面的工作代码:
composer require nicmart/tree
这是文件
<?php
require 'vendor/autoload.php';
$array = json_decode('{"reeta.datetime_day":{"buckets":[{"key_as_string":"2018-07-27T00:00:00.000Z","key":1532649600000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":3,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":3,"ticket.total_guest_count":{"value":17},"ticket.total_revenue":{"value":273}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":195}}]}}]}},{"key_as_string":"2018-07-28T00:00:00.000Z","key":1532736000000,"doc_count":6,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":3,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":212}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":112}}]}},{"key":"Dorothea Friesen","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":379.97999572753906}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":226.35000610351562}}]}}]}},{"key_as_string":"2018-07-29T00:00:00.000Z","key":1532822400000,"doc_count":0,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[]}},{"key_as_string":"2018-07-30T00:00:00.000Z","key":1532908800000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":105.3499984741211}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":160.35000610351562}}]}}]}},{"key_as_string":"2018-07-31T00:00:00.000Z","key":1532995200000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":234}}]}}]}},{"key_as_string":"2018-08-01T00:00:00.000Z","key":1533081600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":151.35000610351562}}]}}]}},{"key_as_string":"2018-08-02T00:00:00.000Z","key":1533168000000,"doc_count":5,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":5}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":140}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":241}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":157}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":240}}]}}]}},{"key_as_string":"2018-08-03T00:00:00.000Z","key":1533254400000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":12},"ticket.total_revenue":{"value":169}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":260.3500061035156}}]}}]}},{"key_as_string":"2018-08-04T00:00:00.000Z","key":1533340800000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":16},"ticket.total_revenue":{"value":277}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":118}}]}}]}},{"key_as_string":"2018-08-05T00:00:00.000Z","key":1533427200000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":68}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":274}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":180}}]}}]}},{"key_as_string":"2018-08-06T00:00:00.000Z","key":1533513600000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":172}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":119}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":120}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":37}}]}}]}},{"key_as_string":"2018-08-07T00:00:00.000Z","key":1533600000000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":134}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":71}}]}}]}},{"key_as_string":"2018-08-08T00:00:00.000Z","key":1533686400000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":252}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":244.35000610351562}}]}}]}},{"key_as_string":"2018-08-09T00:00:00.000Z","key":1533772800000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":246}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":23}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":34}}]}}]}},{"key_as_string":"2018-08-10T00:00:00.000Z","key":1533859200000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":77.3499984741211}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":195}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":85}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":161}}]}}]}},{"key_as_string":"2018-08-11T00:00:00.000Z","key":1533945600000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":38}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":25}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":100}}]}}]}},{"key_as_string":"2018-08-12T00:00:00.000Z","key":1534032000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":201}}]}}]}},{"key_as_string":"2018-08-13T00:00:00.000Z","key":1534118400000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":15},"ticket.total_revenue":{"value":183.3499984741211}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":116}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":117}}]}}]}},{"key_as_string":"2018-08-14T00:00:00.000Z","key":1534204800000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":11},"ticket.total_revenue":{"value":255}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":73.3499984741211}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":7}}]}}]}},{"key_as_string":"2018-08-15T00:00:00.000Z","key":1534291200000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":101}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":10},"ticket.total_revenue":{"value":31}}]}}]}},{"key_as_string":"2018-08-16T00:00:00.000Z","key":1534377600000,"doc_count":0,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[]}},{"key_as_string":"2018-08-17T00:00:00.000Z","key":1534464000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":155}}]}}]}},{"key_as_string":"2018-08-18T00:00:00.000Z","key":1534550400000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":130.35000610351562}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":255.97999572753906}}]}}]}},{"key_as_string":"2018-08-19T00:00:00.000Z","key":1534636800000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":176}}]}}]}},{"key_as_string":"2018-08-20T00:00:00.000Z","key":1534723200000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":290.3500061035156}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":88}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":88}}]}}]}},{"key_as_string":"2018-08-21T00:00:00.000Z","key":1534809600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":64}}]}}]}},{"key_as_string":"2018-08-22T00:00:00.000Z","key":1534896000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":171.35000610351562}}]}}]}},{"key_as_string":"2018-08-23T00:00:00.000Z","key":1534982400000,"doc_count":5,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":11},"ticket.total_revenue":{"value":112}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":120}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":73.3499984741211}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":149}}]}}]}},{"key_as_string":"2018-08-24T00:00:00.000Z","key":1535068800000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":10},"ticket.total_revenue":{"value":56}}]}}]}},{"key_as_string":"2018-08-25T00:00:00.000Z","key":1535155200000,"doc_count":6,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":14},"ticket.total_revenue":{"value":228.35000038146973}}]}},{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":27}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":154}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":114}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":13.350000381469727}}]}}]}},{"key_as_string":"2018-08-26T00:00:00.000Z","key":1535241600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":244}}]}}]}}]}}', true);
$dimensions = ['reeta.datetime_day', 'ticket.employee_name', 'ticket.order_type'];
$metrics = ['ticket.total_guest_count', 'ticket.total_revenue'];
use Tree\Node\Node;
class TableFormatter
{
public static function formatDataTable($aggregationResults, array $dimensions, array $metrics) {
// initialize main data to return
$data = [];
$headerRow = [];
// now put in each metric we have
foreach($dimensions as $dimension) {
array_push($headerRow, $dimension);
}
// now put in each metric we have
foreach($metrics as $metric) {
array_push($headerRow, $metric);
}
$data[] = $headerRow;
$aggs = self::convertToTree($aggregationResults, $dimensions, $metrics);
return array_merge($data, $aggs);
}
private static function convertToTree(array $aggregationResults, array $dimensions, array $metrics, $tree = null, & $data = []) {
// initialize a tree if there isn't one already
if (!$tree) {
$tree = new Node('root');
}
// if there are dimensions then continue
if (!empty($dimensions)) {
// get the next dimension
$dimension = array_shift($dimensions);
// ensure the data is set for that dimension
if (isset($aggregationResults[$dimension]['buckets'])) {
// loop through each buckt
foreach ($aggregationResults[$dimension]['buckets'] as $bucket) {
// make child node to store the value and add to the parent node
$dimensionValue = new Node($bucket['key']);
$tree->addChild($dimensionValue);
// recursively call function to traverse through each bucket
self::convertToTree($bucket, $dimensions, $metrics, $dimensionValue, $data);
}
} else {
throw new Exception("No aggregation data for [".$dimension."]", Error::ERROR_INTERNAL_ERROR);
}
} else {
self::formatMetricData($aggregationResults, $metrics, $tree, $data);
}
return $data;
}
private static function formatMetricData(array $bucket, array $metrics, $tree, & $data) {
if(empty($bucket)) {
return $tree;
}
// setup the array for the table row
$item = [];
// now add each metric
foreach($metrics as $metric) {
$metricValue = new Node($bucket[$metric]['value']);
// add in the metrics
$item[] = $metricValue->getValue();
$tree->addChild($metricValue);
}
// metrics are the wrong way round at this point so reverse them
$item = array_reverse($item);
// add in the key
$item[] = $bucket['key'];
// now we can traverse the tree all the way up and get the parents
$node = $tree->getParent();
while ($node->getValue() != 'root') {
$item[] = $node->getValue();
$node = $node->getParent();
}
// reverse here as it's in the wrong order
$data[] = array_reverse($item);
return $tree;
}
}
$result = TableFormatter::formatDataTable($array, $dimensions, $metrics);
var_dump($result);
如前所述,这绝对不是目前为止最有效的解决方案,但它确实有效,并且花了很多时间四处寻找类似的东西,所以希望这可以帮助解除封锁,直到出现更好的解决方案。
谢谢!
我正在尝试弄清楚如何将嵌套的 array/tree 扁平化为 CSV 样式格式。
我有一个来自 elasticsearch 的结果,如下所示(注意 - 每个 'buckets' 属性 可以有多个或 0 个项目):
$data = array(
'reeta.datetime_day' => array(
'buckets' => array(
0 => array(
'key_as_string' => '2018-07-27T00:00:00.000Z',
'key' => 1532649600000,
'doc_count' => 4,
'ticket.employee_name' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Era Swift',
'doc_count' => 3,
'ticket.order_type' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Dine In',
'doc_count' => 3,
'ticket.total_guest_count' => array(
'value' => 17,
) ,
'ticket.total_revenue' => array(
'value' => 273,
) ,
) ,
) ,
) ,
) ,
1 => array(
'key' => 'Dorothea Friesen',
'doc_count' => 1,
'ticket.order_type' => array(
'doc_count_error_upper_bound' => 0,
'sum_other_doc_count' => 0,
'buckets' => array(
0 => array(
'key' => 'Take Out',
'doc_count' => 1,
'ticket.total_guest_count' => array(
'value' => 2,
) ,
'ticket.total_revenue' => array(
'value' => 195,
) ,
) ,
) ,
) ,
) ,
) ,
) ,
)
)
)
);
我有一个用于获取这些聚合的维度和指标列表,它们各不相同,例如,上面的结果使用以下内容:
$dimensions = ['reeta.datetime_day', 'ticket.employee_name', 'ticket.order_type'];
$metrics = ['ticket.total_guest_count', 'ticket.total_revenue'];
我希望是这样的:
$result = [
// the first bucket of the deepest dimension (ticket.order_type)
[
1532649600000, // the first dimensions key value
'Era Swift', // the second dimensions key value
'Dine In', // the thirs dimensions key value
17, // the first metrics value
273 // the second metrics value
],
// the second bucket of the deepest dimension (ticket.order_type)
[
1532649600000, // the first dimensions key value
'Dorothea Friesen', // the second dimensions key value
'Take Out', // the thirs dimensions key value
2, // the first metrics value
195 // the second metrics value
],
];
为了更好地解释我的用例,我创建了一个 API,它接受许多维度和指标,然后查询 ES 以获得结果。然后,我将获取这些结果并使用它们为 Google 图表 (https://developers.google.com/chart/interactive/docs/datatables_dataviews).
创建数据表我尝试编写许多递归函数,array_walk_recursive 等,并尝试使用谷歌搜索任何类似的示例,但找不到任何地方。
我尝试遍历并检查:
$array[$dimension]['buckets']
要知道当索引不存在时我处于最深层次
但我总是得到不正确的结果。我只是无法简单地展平数组,因为我需要为每个最深层次的桶提供一个数组项。
希望这能说得通,但我很乐意在这里澄清并提供更大的数据集: https://pastebin.com/mU2xkQGB
如果有人能指出我正确的方向或任何类似的示例,我将不胜感激,我确实有一堆嵌套的 foreach 块在某个时候工作,但一旦我改变维度的数量当然没用。
我确实设法找到了一种解决方案,它绝对不是最好的,但它通常适用于任意数量的维度和指标。
本质上,我使用 https://github.com/nicmart/Tree 构建了一个树对象,因此可以遍历节点,但是我想要,所以每次我必须添加指标时,我都可以遍历回到它的父节点并创建一个 table 行。
查看下面的工作代码:
composer require nicmart/tree
这是文件
<?php
require 'vendor/autoload.php';
$array = json_decode('{"reeta.datetime_day":{"buckets":[{"key_as_string":"2018-07-27T00:00:00.000Z","key":1532649600000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":3,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":3,"ticket.total_guest_count":{"value":17},"ticket.total_revenue":{"value":273}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":195}}]}}]}},{"key_as_string":"2018-07-28T00:00:00.000Z","key":1532736000000,"doc_count":6,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":3,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":212}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":112}}]}},{"key":"Dorothea Friesen","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":379.97999572753906}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":226.35000610351562}}]}}]}},{"key_as_string":"2018-07-29T00:00:00.000Z","key":1532822400000,"doc_count":0,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[]}},{"key_as_string":"2018-07-30T00:00:00.000Z","key":1532908800000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":105.3499984741211}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":160.35000610351562}}]}}]}},{"key_as_string":"2018-07-31T00:00:00.000Z","key":1532995200000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":234}}]}}]}},{"key_as_string":"2018-08-01T00:00:00.000Z","key":1533081600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":151.35000610351562}}]}}]}},{"key_as_string":"2018-08-02T00:00:00.000Z","key":1533168000000,"doc_count":5,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":5}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":140}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":241}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":157}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":240}}]}}]}},{"key_as_string":"2018-08-03T00:00:00.000Z","key":1533254400000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":12},"ticket.total_revenue":{"value":169}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":260.3500061035156}}]}}]}},{"key_as_string":"2018-08-04T00:00:00.000Z","key":1533340800000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":16},"ticket.total_revenue":{"value":277}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":118}}]}}]}},{"key_as_string":"2018-08-05T00:00:00.000Z","key":1533427200000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":68}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":274}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":180}}]}}]}},{"key_as_string":"2018-08-06T00:00:00.000Z","key":1533513600000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":172}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":119}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":120}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":37}}]}}]}},{"key_as_string":"2018-08-07T00:00:00.000Z","key":1533600000000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":134}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":71}}]}}]}},{"key_as_string":"2018-08-08T00:00:00.000Z","key":1533686400000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":252}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":244.35000610351562}}]}}]}},{"key_as_string":"2018-08-09T00:00:00.000Z","key":1533772800000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":246}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":23}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":34}}]}}]}},{"key_as_string":"2018-08-10T00:00:00.000Z","key":1533859200000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":77.3499984741211}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":195}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":85}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":161}}]}}]}},{"key_as_string":"2018-08-11T00:00:00.000Z","key":1533945600000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":2},"ticket.total_revenue":{"value":38}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":25}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":100}}]}}]}},{"key_as_string":"2018-08-12T00:00:00.000Z","key":1534032000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":201}}]}}]}},{"key_as_string":"2018-08-13T00:00:00.000Z","key":1534118400000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":15},"ticket.total_revenue":{"value":183.3499984741211}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":116}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":117}}]}}]}},{"key_as_string":"2018-08-14T00:00:00.000Z","key":1534204800000,"doc_count":4,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":11},"ticket.total_revenue":{"value":255}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":73.3499984741211}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":7}}]}}]}},{"key_as_string":"2018-08-15T00:00:00.000Z","key":1534291200000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":101}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":10},"ticket.total_revenue":{"value":31}}]}}]}},{"key_as_string":"2018-08-16T00:00:00.000Z","key":1534377600000,"doc_count":0,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[]}},{"key_as_string":"2018-08-17T00:00:00.000Z","key":1534464000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":155}}]}}]}},{"key_as_string":"2018-08-18T00:00:00.000Z","key":1534550400000,"doc_count":2,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":130.35000610351562}}]}},{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":255.97999572753906}}]}}]}},{"key_as_string":"2018-08-19T00:00:00.000Z","key":1534636800000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":176}}]}}]}},{"key_as_string":"2018-08-20T00:00:00.000Z","key":1534723200000,"doc_count":3,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":290.3500061035156}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":88}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":88}}]}}]}},{"key_as_string":"2018-08-21T00:00:00.000Z","key":1534809600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":64}}]}}]}},{"key_as_string":"2018-08-22T00:00:00.000Z","key":1534896000000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":171.35000610351562}}]}}]}},{"key_as_string":"2018-08-23T00:00:00.000Z","key":1534982400000,"doc_count":5,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":2,"ticket.total_guest_count":{"value":11},"ticket.total_revenue":{"value":112}}]}},{"key":"Conor Gerlach","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":6},"ticket.total_revenue":{"value":120}}]}},{"key":"Dorothea Friesen","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":73.3499984741211}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":1},"ticket.total_revenue":{"value":149}}]}}]}},{"key_as_string":"2018-08-24T00:00:00.000Z","key":1535068800000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":10},"ticket.total_revenue":{"value":56}}]}}]}},{"key_as_string":"2018-08-25T00:00:00.000Z","key":1535155200000,"doc_count":6,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Conor Gerlach","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":2,"ticket.total_guest_count":{"value":14},"ticket.total_revenue":{"value":228.35000038146973}}]}},{"key":"Era Swift","doc_count":2,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":8},"ticket.total_revenue":{"value":27}},{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":9},"ticket.total_revenue":{"value":154}}]}},{"key":"Delbert Abernathy","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":5},"ticket.total_revenue":{"value":114}}]}},{"key":"Foster Bashirian","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Take Out","doc_count":1,"ticket.total_guest_count":{"value":3},"ticket.total_revenue":{"value":13.350000381469727}}]}}]}},{"key_as_string":"2018-08-26T00:00:00.000Z","key":1535241600000,"doc_count":1,"ticket.employee_name":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Era Swift","doc_count":1,"ticket.order_type":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Dine In","doc_count":1,"ticket.total_guest_count":{"value":4},"ticket.total_revenue":{"value":244}}]}}]}}]}}', true);
$dimensions = ['reeta.datetime_day', 'ticket.employee_name', 'ticket.order_type'];
$metrics = ['ticket.total_guest_count', 'ticket.total_revenue'];
use Tree\Node\Node;
class TableFormatter
{
public static function formatDataTable($aggregationResults, array $dimensions, array $metrics) {
// initialize main data to return
$data = [];
$headerRow = [];
// now put in each metric we have
foreach($dimensions as $dimension) {
array_push($headerRow, $dimension);
}
// now put in each metric we have
foreach($metrics as $metric) {
array_push($headerRow, $metric);
}
$data[] = $headerRow;
$aggs = self::convertToTree($aggregationResults, $dimensions, $metrics);
return array_merge($data, $aggs);
}
private static function convertToTree(array $aggregationResults, array $dimensions, array $metrics, $tree = null, & $data = []) {
// initialize a tree if there isn't one already
if (!$tree) {
$tree = new Node('root');
}
// if there are dimensions then continue
if (!empty($dimensions)) {
// get the next dimension
$dimension = array_shift($dimensions);
// ensure the data is set for that dimension
if (isset($aggregationResults[$dimension]['buckets'])) {
// loop through each buckt
foreach ($aggregationResults[$dimension]['buckets'] as $bucket) {
// make child node to store the value and add to the parent node
$dimensionValue = new Node($bucket['key']);
$tree->addChild($dimensionValue);
// recursively call function to traverse through each bucket
self::convertToTree($bucket, $dimensions, $metrics, $dimensionValue, $data);
}
} else {
throw new Exception("No aggregation data for [".$dimension."]", Error::ERROR_INTERNAL_ERROR);
}
} else {
self::formatMetricData($aggregationResults, $metrics, $tree, $data);
}
return $data;
}
private static function formatMetricData(array $bucket, array $metrics, $tree, & $data) {
if(empty($bucket)) {
return $tree;
}
// setup the array for the table row
$item = [];
// now add each metric
foreach($metrics as $metric) {
$metricValue = new Node($bucket[$metric]['value']);
// add in the metrics
$item[] = $metricValue->getValue();
$tree->addChild($metricValue);
}
// metrics are the wrong way round at this point so reverse them
$item = array_reverse($item);
// add in the key
$item[] = $bucket['key'];
// now we can traverse the tree all the way up and get the parents
$node = $tree->getParent();
while ($node->getValue() != 'root') {
$item[] = $node->getValue();
$node = $node->getParent();
}
// reverse here as it's in the wrong order
$data[] = array_reverse($item);
return $tree;
}
}
$result = TableFormatter::formatDataTable($array, $dimensions, $metrics);
var_dump($result);
如前所述,这绝对不是目前为止最有效的解决方案,但它确实有效,并且花了很多时间四处寻找类似的东西,所以希望这可以帮助解除封锁,直到出现更好的解决方案。
谢谢!