Using a PHP variable to aggregate in MongoDB - php

I've been trying to use PHP Variables to get results from a mongoDB database.
This works:
//create Mongo connection
$m = new MongoClient();
//Select db
$db = $m->warehouse;
//create collection
$fact = $db->fact;
$res = $fact->aggregate([
array(
'$match'=>array(
'day'=>array('$gte'=>3,'$lte'=>28),
'month'=>array('$gte'=>3,'$lte'=>3),
'year'=>array('$gte'=>2017,'$lte'=>2017)
)
),
array(
'$group'=>array(
'_id'=>array(
'month'=>'$month',
'day'=>'$day',
'year'=>'$year'
),
'totalSales'=>array('$sum'=>'$sale'),
'totalCost'=>array('$sum'=>'$total_cost')
)
),
array(
'$project'=>array(
'_id'=>0,
'totalSales'=>1,
'totalCost'=>1,
'totalProfit'=>array(
'$subtract'=>['$totalSales','$totalCost']
)
)
)
]);
Output of var_dump($res):
array (size=3)
'waitedMS' => int 0
'result' =>
array (size=1)
0 =>
array (size=3)
'totalSales' => float 440
'totalCost' => float 350
'totalProfit' => float 90
'ok' => float 1
But When I try to replace the numbers with php variables like:
$res = $fact->aggregate([
array(
'$match'=>array(
'day'=>array('$gte'=>$dayfrom,'$lte'=>$dayto),
'month'=>array('$gte'=>$monthfrom,'$lte'=>$monthto),
'year'=>array('$gte'=>$yearfrom,'$lte'=>$yearto)
)
),
array(
'$group'=>array(
'_id'=>array(
'month'=>'$month',
'day'=>'$day',
'year'=>'$year'
),
'totalSales'=>array('$sum'=>'$sale'),
'totalCost'=>array('$sum'=>'$total_cost')
)
),
array(
'$project'=>array(
'_id'=>0,
'totalSales'=>1,
'totalCost'=>1,
'totalProfit'=>array(
'$subtract'=>['$totalSales','$totalCost']
)
)
)
]);
I don't get back any results:
array (size=3)
'waitedMS' => int 0
'result' =>
array (size=0)
empty
'ok' => float 1
What am I doing wrong here? I have tried several things like putting the PHP variables under single quotes or trying to put parts of the query into strings and using those strings to re-build the query but nothing seems to work excep for the hard-coded numbers into the aggregation. Any idea what's going on here?
EDIT: (This did the trick)
Tried initializing the variables in a PHP class constructor that explicitly specifies that the value is coming from a PHP variable:
class DateSet {
public $df;
public $dt;
public $mf;
public $mt;
public $yf;
public $yt;
function __construct( $df, $dt, $mf, $mt, $yf, $yt) {
$this->df = $df;
$this->dt = $dt;
$this->mf = $mf;
$this->mt = $mt;
$this->yf = $yf;
$this->yt = $yt;
}
};
$dateobj = new DateSet($dayfrom,$dayto,$monthfrom,$monthto,$yearfrom,$yearto);
$res = $fact->aggregate([
array(
'$match'=>array(
'day'=>array('$gte'=>$dateobj->df,'$lte'=>$dateobj->dt),
'month'=>array('$gte'=>$dateobj->mf,'$lte'=>$dateobj->mt),
'year'=>array('$gte'=>$dateobj->yf,'$lte'=>$dateobj->yt)
)
),
array(
'$group'=>array(
'_id'=>array(
'month'=>'$month',
'day'=>'$day',
'year'=>'$year'
),
'totalSales'=>array('$sum'=>'$sale'),
'totalCost'=>array('$sum'=>'$total_cost')
)
),
array(
'$project'=>array(
'_id'=>0,
'totalSales'=>1,
'totalCost'=>1,
'totalProfit'=>array(
'$subtract'=>['$totalSales','$totalCost']
)
)
)
]);
OUTPUT:
array (size=3)
'waitedMS' => int 0
'result' =>
array (size=7)
0 =>
array (size=3)
'totalSales' => float 640
'totalCost' => float 520
'totalProfit' => float 120
1 =>
array (size=3)
'totalSales' => float 8000
'totalCost' => float 6000
'totalProfit' => float 2000
2 =>
array (size=3)
'totalSales' => float 700
'totalCost' => float 600
'totalProfit' => float 100
3 =>
array (size=3)
'totalSales' => float 18000
'totalCost' => float 15000
'totalProfit' => float 3000
4 =>
array (size=3)
'totalSales' => float 6300
'totalCost' => float 6100
'totalProfit' => float 200
5 =>
array (size=3)
'totalSales' => float 68503
'totalCost' => float 55720
'totalProfit' => float 12783
6 =>
array (size=3)
'totalSales' => float 440
'totalCost' => float 350
'totalProfit' => float 90
'ok' => float 1

Related

How to store a binary tree as one-dimensional array?

How to construct data into a binary tree sort to output a one-dimensional array?
Now that I have constructed the data into a binary tree, how can I recursively solve the binary tree as a one-dimensional array with the following code and data:
Data
$nodes = array(8,3,10,1,6,14,4,7,13);
Construct a binary tree code
function insertNode($node,$newNode){
//var_dump($node);
//var_dump($newNode);
//exit;
if ($node['key'] < $newNode['key']){
if (empty($node['right'])){
$node['right'] = $newNode;
}else{
$node['right'] = insertNode($node['right'],$newNode);
}
}elseif ($node['key'] > $newNode['key']){
if (empty($node['left'])){
$node['left'] = $newNode;
}else{
$node['left'] = insertNode($node['left'],$newNode);
}
}
return $node;
}
function tree($nodes)
{
$node = [
'key' => '',
'left' => '',
'right' => ''
];
$newNode = [
'key' => '',
'left' => '',
'right'=> ''
];
foreach ($nodes as $key => $value){
//insert($value,$key);
if($key == 0)
{
$node['key'] = $value;
continue;
}
$newNode['key'] = $value;
//Constructing a binary tree
$node = insertNode($node,$newNode);
}
//Recursive solution
$node = midSortNode($node);
return $node;
}
var_dump(tree($nodes));
The following is my constructed binary tree
array (size=3)
'key' => int 8
'left' =>
array (size=3)
'key' => int 3
'left' =>
array (size=3)
'key' => int 1
'left' => string '' (length=0)
'right' => string '' (length=0)
'right' =>
array (size=3)
'key' => int 6
'left' =>
array (size=3)
...
'right' =>
array (size=3)
...
'right' =>
array (size=3)
'key' => int 10
'left' => string '' (length=0)
'right' =>
array (size=3)
'key' => int 14
'left' =>
array (size=3)
...
'right' => string '' (length=0)
I need to recursively classify the binary tree into a well-ordered one-dimensional array.
My code is as follows
function midSortNode($node){
$sortArr = [];
if (!empty($node)){
$sortArr[] = midSortNode($node['left']);
//$sortArr['left'] = midSortNode($node['left']);
array_push($sortArr,$node['key']);
$sortArr[] = midSortNode($node['right']);
//$sortArr['right'] = midSortNode($node['right']);
}
return $sortArr;
}
var_dump(midSortNode($node));
Here is the result, but not what I want
0 =>
array (size=3)
0 =>
array (size=3)
0 =>
array (size=0)
...
1 => int 1
2 =>
array (size=0)
...
1 => int 3
2 =>
array (size=3)
0 =>
array (size=3)
...
1 => int 6
2 =>
array (size=3)
...
1 => int 8
2 =>
array (size=3)
0 =>
array (size=0)
empty
1 => int 10
2 =>
array (size=3)
0 =>
array (size=3)
...
1 => int 14
2 =>
array (size=0)
...
How to solve the binary tree as follows
array (size=9)
0 => int 1
1 => int 3
2 => int 4
3 => int 6
4 => int 7
5 => int 8
6 => int 10
7 => int 13
8 => int 14
I'm assuming that your happy with the steps so far, so the main code as it is isn't changed. All I think you need to do is to extract the data from the final tree into a 1 dimensional array. As the items are all leaf nodes and in order, you can just use array_walk_recursive() to go over all of the nodes and add them to a new array...
$tree = tree($nodes);
array_walk_recursive( $tree,
function ($data) use (&$output) { $output[] = $data;} );
print_r($output);
gives...
Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 6
[4] => 7
[5] => 8
[6] => 10
[7] => 13
[8] => 14
)
Edit:
To update the existing code to do this, you can change the midSortNode() to pass around the list of outputs and only add in the current node...
function midSortNode($node, $sortArr = []){
if (!empty($node)){
$sortArr = midSortNode($node['left'], $sortArr);
$sortArr[] = $node['key'];
$sortArr = midSortNode($node['right'], $sortArr);
}
return $sortArr;
}

PHP Apply multiple callback functions when using array_map, array_walk etc. functions

I have encountered an array of serialized values like below:
Array
(
[primary] => Array
(
[key_type_0_key_name] => a:1:{i:0;s:5:"27232";}
[key_type_1_key_name] => a:1:{i:0;s:5:"27231";}
[key_type_2_key_name] => a:1:{i:0;s:5:"27147";}
[key_type_3_key_name] => a:1:{i:0;s:5:"27157";}
)
[additional] => Array
(
[key_type_0_key_othername] => a:1:{i:0;s:5:"27169";}
[key_type_1_key_othername] => a:1:{i:0;s:5:"27160";}
[key_type_2_key_othername] => a:1:{i:0;s:5:"27103";}
[key_type_3_key_othername] => a:1:{i:0;s:5:"27149";}
)
)
Now I need to apply two functions namely, unserialize and array_shift in specified order to extract the scalar values like 27169 and store in another array, how can I do that in one pass of array_map or I have to run array_map two times compulsorily ?
Also one problem is with recursion, only array_walk_recursive handles recursion properly, but in my case if I try below code, I am getting the given error:
return array_walk_recursive($array, function ( &$value ) {
$value = array_shift( unserialize( $value ) );
});
Error:
Strict Standards: Only variables should be passed by reference in /path/to/file.php on line 367
Expected Result:
Array
(
[primary] => Array
(
27232
27231
27147
27157
)
[additional] => Array
(
27169
27160
27103
27149
)
)
With no calls to array_map.
<?php
$data = [
'primary' =>
[
'a:1:{i:0;s:5:"27232";}',
'a:1:{i:0;s:5:"27231";}',
'a:1:{i:0;s:5:"27147";}',
'a:1:{i:0;s:5:"27157";}'
],
'additional' =>
[
'a:1:{i:0;s:5:"27169";}',
'a:1:{i:0;s:5:"27160";}',
'a:1:{i:0;s:5:"27103";}',
'a:1:{i:0;s:5:"27149";}'
]
];
$numbers = [];
foreach($data as $key=>$value) {
foreach($value as $k=>$v) {
$unserialized = unserialize($v);
$numbers[$key][] = (int) array_shift($unserialized);
}
}
var_dump($numbers);
Output:
array (size=2)
'primary' =>
array (size=4)
0 => int 27232
1 => int 27231
2 => int 27147
3 => int 27157
'additional' =>
array (size=4)
0 => int 27169
1 => int 27160
2 => int 27103
3 => int 27149
Here a mutating array_walk example with three array_map calls. Far uglier and harder to read in my eyes, but each their own:
array_walk($data, function(&$v) {
$v = array_map('intval', array_map('array_shift', array_map('unserialize', $v)));
}
);
var_dump($data);
Output:
array (size=2)
'primary' =>
array (size=4)
0 => int 27232
1 => int 27231
2 => int 27147
3 => int 27157
'additional' =>
array (size=4)
0 => int 27169
1 => int 27160
2 => int 27103
3 => int 27149
Allow me to answer the question that was asked. Yes, yes you can... and you nearly had it!
You only needed to change the way that you were accessing the value. Replace the array_shift() call with [0] -- this eliminates the Strict Standards error.
Code: (Demo)
$array=[
'primary' =>
[
'a:1:{i:0;s:5:"27232";}',
'a:1:{i:0;s:5:"27231";}',
'a:1:{i:0;s:5:"27147";}',
'a:1:{i:0;s:5:"27157";}'
],
'additional' =>
[
'a:1:{i:0;s:5:"27169";}',
'a:1:{i:0;s:5:"27160";}',
'a:1:{i:0;s:5:"27103";}',
'a:1:{i:0;s:5:"27149";}'
]
];
array_walk_recursive($array,function(&$v){$v=unserialize($v)[0];});
var_export($array);
Output:
array (
'primary' =>
array (
0 => '27232',
1 => '27231',
2 => '27147',
3 => '27157',
),
'additional' =>
array (
0 => '27169',
1 => '27160',
2 => '27103',
3 => '27149',
),
)

Php Array from database not getting desired array stucture

I have problem with building multi-dimensional array by pulling data from database.
I have a list of Sales Representative (sr) in my database. I run query and selected all sr.
Now I have to create array like this:
array (size=3)
'Manoj' =>
array (size=3)
'mc_count' => 0
'auto_count' => 0
'in_count' => 0
'Bharat' =>
array (size=3)
'mc_count' => 0
'auto_count' => 0
'in_count' => 0
'Pradeep' =>
array (size=3)
'mc_count' => 0
'auto_count' => 0
'in_count' => 0
To create this I have written following code:
<?php
$sr_array=array();
$sr_sql= "select DISTINCT sr from sales_invoice";
$sr_query = mysqli_query($connection, $sr_sql);
while($sr_result = mysqli_fetch_assoc($sr_query)){
$sr_array []= array($sr_result["sr"]=>array(“mc_count”,”auto_count”,”in_coun”);
}
var_dump($sr_array);
?>
I get this OUTPUT
array (size=9)
0 =>
array (size=1)
'Manoj' =>
array (size=3)
'count_in_battery' => int 10
'count_auto_battety' => int 0
'count_indu_battery' => int 0
1 =>
array (size=1)
'Bharat' =>
array (size=3)
'count_in_battery' => int 10
'count_auto_battety' => int 0
'count_indu_battery' => int 0
2 =>
array (size=1)
'Pradeep =>
array (size=3)
'count_in_battery' => int 10
'count_auto_battety' => int 0
'count_indu_battery' => int 0
If you see the output my array has additional index as
0 => //Unwanted Index
array (size=1)
'Manoj' =>
Which is creating problem in programming. If you can please help me.
Try this:
$sr_array = array();
$sr_sql = "select DISTINCT sr from sales_invoice";
$sr_query = mysqli_query($connection, $sr_sql);
while($sr_result = mysqli_fetch_assoc($sr_query)){
$sr_array[$sr_result["sr"]] = array(
"mc_count" => 0,
"auto_count" => 0,
"in_coun" => 0
);
}

Issue about correct and fast seeking in array

I have a question about correct and fast seeking in php array.
I have input array:
array (size=2)
0 =>
array (size=7)
'Videos' =>
array (size=2)
240 =>
array (size=2)
...
120 =>
array (size=2)
...
'Texts' =>
array (size=0)
empty
'Price' => float 0
'QaAudio' => int 1
'QaVideo' => int 3
'Level' => string 'normal' (length=6)
'PreviewPic' =>
array (size=7)
40 =>
array (size=12)
...
60 =>
array (size=12)
...
140 =>
array (size=12)
...
160 =>
array (size=12)
...
320 =>
array (size=12)
...
640 =>
array (size=12)
...
1024 =>
array (size=12)
...
1 =>
array (size=7)
'Videos' =>
array (size=3)
480 =>
array (size=2)
...
360 =>
array (size=2)
...
120 =>
array (size=2)
...
'Texts' =>
array (size=0)
empty
'Price' => float 0
'QaAudio' => int 1
'QaVideo' => int 3
'Level' => string 'sexy' (length=4)
'PreviewPic' =>
array (size=7)
40 =>
array (size=12)
...
60 =>
array (size=12)
...
140 =>
array (size=12)
...
160 =>
array (size=12)
...
320 =>
array (size=12)
...
640 =>
array (size=12)
...
1024 =>
array (size=12)
...
I need to find in it the video, that has max value in Videos key.(it has 360,240,120 values as you can see in example) and has Level Key that equal to 'normal' or 'sexy' value.
I wrote some method to do it:
public function getPresentationVideo($id)
{
$result = [];
$notHardVideos = [];
$profileVideos = $this->getProfilesVideos($id,0,50);
if ($profileVideos && count($profileVideos) > 0) {
foreach ($profileVideos as $video) {
if (in_array($video['Level'],['normal','sexy'])) {
$video['maxVideoQuality'] = max(array_keys($video['Videos']));
$notHardVideos[] = $video;
}
}
$keyForMaxQuality = 0;
if (count($notHardVideos) > 1) {
$maxQuality = 0;
foreach($notHardVideos as $key => $video) {
if($video['maxVideoQuality'] > $maxQuality)
{
$maxQuality = $video['maxVideoQuality'];
$keyForMaxQuality = $key;
}
}
}
if (count($notHardVideos) > 0) {
$result = $notHardVideos[$keyForMaxQuality];
unset($result['maxVideoQuality']);
}
}
return $result;
}
It do it well.
But i wonder is there any more effective way to do it.
Do you have any ideas?
Thanks in advance.
$result = array_reduce($videos, function ($result, array $video) {
if (!in_array($video['Level'], ['normal', 'sexy'])) {
return $result;
}
if (!$result) {
return $video;
}
if (max(array_keys($video['Videos'])) > max(array_keys($result['Videos']))) {
return $video;
}
return $result;
});
This will return the sub array which has a 'normal' or 'sexy' level (BTW, FTW?!) and which has the highest key in its 'Videos' sub array. It doesn't include any other considerations, as you seem to have in your code, because you did not specify exactly what those considerations are. However, you should get the idea and can add more checks if you need.
See http://php.net/array_reduce for help with this function. In short, this takes each element in the array in turn and compares it to the previous best candidate. I.e., $result will be nothing at first, but when you have found a 'normal' or 'sexy' video it will become that video, and on subsequent calls the video with the higher keys will win.

settype() in PHP for an ARRAY is producing Different output

CODE 1: Reading data from Excel sheet. Containing 12 Different values.
The values are : 48,600,5.3,5,1500,6000,85,30,70,30,70,14 .
$BATTCONFIG=$objPHPExcel->getActiveSheet()->rangetoArray('C9:C20',null,true,true,true);
CODE 2: Trying to convert all VALUES in the array $BATTCONFIG to INTEGER using FOR loop.
$y1 = (array_values($BATTCONFIG));
var_dump(y1);
for( $i=0 ; $i<=11 ; $i++ )
{
settype($y1[$i], "integer");
}
var_dump($y1);
But I am not getting the desiered output , I am getting all the values as 1 .
MY OUTPUT:
Before SETTYPE():
array (size=12)
0 =>
array (size=1)
'C' => float 48
1 =>
array (size=1)
'C' => int 600
2 =>
array (size=1)
'C' => float 0.3
3 =>
array (size=1)
'C' => int 5
4 =>
array (size=1)
'C' => float 1500
5 =>
array (size=1)
'C' => int 6000
6 =>
array (size=1)
'C' => int 85
7 =>
array (size=1)
'C' => int 30
8 =>
array (size=1)
'C' => int 70
9 =>
array (size=1)
'C' => int 30
10 =>
array (size=1)
'C' => int 70
11 =>
array (size=1)
'C' => float 14
AFTER SETTYPE():
array (size=12)
0 => int 1
1 => int 1
2 => int 1
3 => int 1
4 => int 1
5 => int 1
6 => int 1
7 => int 1
8 => int 1
9 => int 1
10 => int 1
11 => int 1
Please help me out . I need these Integer values as output to plot my Graph.
Thank you in advance.
There must be another error when populating $y1 with its values. Imagine this simplified example which works as expected:
$arr = array('1','2','3','4','5');
for ($i = 0; $i < 5; $i++) {
settype($arr[$i], "integer");
}
var_dump($arr);
What gives you :
array(5) {
[0] =>
int(1)
[1] =>
int(2)
[2] =>
int(3)
[3] =>
int(4)
[4] =>
int(5)
}
After edit of the question (now having $y1 before conversion) it points out, that you aren't aware of that $y1 is multidimensional array. You'll have to change to code to something like this:
$ints = array();
foreach($y1 as $index => $cell) {
$values = array_values($cell);
$ints []= intval(round($values[0]));
}
var_dump($ints);
Also note, that you are trying to convert floats to int using the settype() function. I would use round() for that

Categories