$sort and $slice along with $addToSet in php mongodb - php

$ret = $this->topusers->update (
array("keyword" => $key),
array('$addToSet' => array("users" => array('$each' => array(array('uname' => $uname, 'counter' => $counter))),
'$sort' => array('counter'=>intval(1))
'$slice' => intval(-2)
)),
array("upsert" => true, "w" => 1)
);
var_dump($ret);
What is wrong with this code ? Tried with $push as well. Will get Modified field name may not start with $ error.
Please help

Found a work-around. To get the mongo command directly working. Full native php version is still eluding me..
This will allow you to update a collection with sorted array and limit the array size as well.
Hope its useful for someone else as well.
$command = 'db.topusers.update( { keyword: "'.$key.'" },'.
'{ $push: { users: { $each : [{ name: "'.$uname.'", counter: '.intval($counter).'}],'.
' $sort: { counter: 1 },'.
' $slice: -2'.
'}'.
'}'.
'},'.
'{upsert : true})';
$this->db->execute($command);

Can you try this,
$ret = $this->topusers->update (
array("keyword" => $key),
array("$addToSet" => array("users" => array("$each" => array(array('uname' => $uname, 'counter' => $counter))),
"$sort" => array('counter'=>intval(1)),
"$slice" => intval(-2)
)),
array("upsert" => true, "w" => 1)
);
var_dump($ret);

You are closing the array()s incorrectly.
Try this:
$ret = $test->topusers->update (
array("keyword" => $key),
array(
'$addToSet' => array(
"users" => array(
'$each' => array(array('uname' => $uname, 'counter' => $counter)),
'$sort' => array('counter'=>intval(1)),
'$slice' => intval(-2)
)
),
),
array("upsert" => true, "w" => 1)
);

Related

Assign values in array based on array keys

How to modify an array based on the value as key?
array(
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220810,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220825,
"totals" => 5614
)
);
I tried the following but it's not working:
foreach($cutoffs as $catoff) {
$ii = 0;
$sums[$ii][$catoff] = array_filter($array, function($val){
return $val['cutoff'] === $catoff ? $val['totals'] : $val;
});
$ii++;
}
My desired array:
array(
'20221025' => array(
12345,
12343,
24442
),
'20221110' => array(
3443,
744334
)
)
I'm stuck here for hours ... Please help
IF the "name" is irrelevant, I think also the previous answer should be fine.
If this code does "not work", then your explanation might be wrong, so you need to either explain better, or give us more examples - please mind that in your example the input and output are very different - the input you gave does not match your ouput.
My code is:
$a = array(
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220810,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 1234
)
);
print_r($a);
echo "\n================================\n\n";
$newArr = [];
foreach ($a as $k => $vArr) {
// maybe some validation would be useful here, check if they keys exist
$newArr[$vArr['cutoff']][] = $vArr['totals'];
}
print_r($newArr);
function changeArr($data){
$new = [];
foreach ($data as $v){
$new[$v['cutoff']][] = $v['totals'];
}
return $new;
}

Writing a HTML string content with array values in Laravel Controller

What I'm trying to accomplish is to write a html string in a controller with array values being looped in it. So for example;
$content = "Your store, at location A, has these items added to them". add array loop here. "Do take note!";
My array would be as such
array (
0 =>
array (
'id' => '5db29b6d31c391731239bbdf',
'name' => 'Diamond bracelet (sample)',
'tags' =>
array (
0 => 'female',
1 => 'jewelry',
),
'category' => 'Accessories',
'sku' => '1029EHW',
'priceType' => 'Fixed',
'unitPrice' => 190,
'cost' => 90,
'trackStockLevel' => true,
'isParentProduct' => false,
),
1 =>
array (
'id' => '5db29b6d31c391731239bbdb',
'name' => 'Long-sleeved shirt(sample)(M)',
'tags' =>
array (
0 => 'tops',
1 => 'cotton',
),
'category' => 'Women\'s Apparel',
'sku' => 'ABC1234-M',
'priceType' => 'Fixed',
'unitPrice' => 47.170000000000002,
'cost' => 20,
'trackStockLevel' => true,
'isParentProduct' => false,
'parentProductId' => '5db29b6d31c391731239bbd4',
'variationValues' =>
array (
0 =>
array (
'variantGroupId' => '5db29b6d31c391731239bbd5',
'value' => 'M',
),
),
),
)
note that the array can have many instances of product_name and sku, or can have none.
How do i populate this in my string to be like;
$content = "Your store, at location A, has these items added to them, 1) asd, 2)def, 3)asf . Do take note!
Try this, I've used \sprintf for ease, check if the output serves your purpose.
<?php
function stringMethod(): string
{
$count = 0;
$arrayString = [];
$array = [['product_name' => 'abc', 'product_sku' => 'def'],['product_name' => 'abc', 'product_sku' => 'asd']];
foreach ($array as $value){
$count++;
$arrayString[] = sprintf('%s)%s', $count, $value['product_sku']);
}
$string = \implode(',', $arrayString);
return \sprintf("Your store, at location A, has these items added to them %s Do take note!", $string);
}
echo stringMethod();
Hope this will help you. try to do it in less number of lines
$content = "Your store, at location A, has these items added to them, ";
$productArray = array (0 => array ('id' => '5db29b6d31c391731239bbdf','name' => 'Diamond bracelet (sample)','tags' => array (0 => 'female',1 => 'jewelry',),'category' => 'Accessories','sku' => '1029EHW','priceType' => 'Fixed','unitPrice' => 190,'cost' => 90,'trackStockLevel' => true,'isParentProduct' => false,),1 => array ('id' => '5db29b6d31c391731239bbdb','name' => 'Long-sleeved shirt(sample)(M)','tags' => array (0 => 'tops',1 => 'cotton',),'category' => 'Women\'s Apparel','sku' => 'ABC1234-M','priceType' => 'Fixed','unitPrice' => 47.170000000000002,'cost' => 20,'trackStockLevel' => true,'isParentProduct' => false,'parentProductId' => '5db29b6d31c391731239bbd4','variationValues' => array (0 => array ('variantGroupId' => '5db29b6d31c391731239bbd5','value' => 'M'))));
foreach ($productArray as $key => $product) {
$content .= ($key+1).') '.$product['name'];
if (count($productArray)-1!=$key) {
$content .= ', ';
}
}
$content .= ". Do take note!";
$content = "Your store, at location A, has these items added to them,". $this->getItemList($collection) .". Do take note!"
# Somewhere else in the controller
protected function getItemList(Collection $collection): string
{
return $collection->pluck('name')
->merge($collection->pluck('sku'))
->map(function($item, $key) {
return ($key + 1) . ') ' . $item;
})
->implode(', ');
}
An easy solution would be
$content = "Your store, at location A, has these items added to them";
$array = array(0=>["product_name" => "abc", "product_sku" => "def"], 1=>['product_name' => 'kdkf', 'product_sku'=> 'ljbkj']);
for($i = 0; $i<count($array); $i++){
$content .= ($i+1).") ".$array[$i]['product_name].' '.$array[$i]['product_sku'].', ';
}
$content .= "Do take note.";
This way you're just constantly concatonating the string value in separate parts instead of trying to inject it in the middle of the parent string.
not tested, may be syntax errors

array_search returns incorrect position

By searching the community and Googleing I can only see issues with array_search loose search resulting integer 0 to be equalled to a string.
However in my case theres no zero and strict search still doesn't seem to help.
Array:
$data= array(
"13" => array(
"start" => array(
0 => "36000",
1 => "43200",
),
"end" => array(
0 => "43200",
1 => "50400",
),
),
"14" => array(
"start" => array(
0 => "36000",
1 => "43200",
),
"end" => array(
0 => "43200",
1 => "50400",
),
),
);
function:
foreach ($data as &$area) {
foreach ($area['start'] as $key => &$start_time) {
if (($pos = array_search($start_time, $area['end'], true) !== false)) {
$area['end'][$pos] = $area['end'][$key];
unset($area['start'][$key]);
unset($area['end'][$key]);
}
}
}
desired output:
$data= array(
"13" => array(
"start" => array(
0 => "36000",
),
"end" => array(
0 => "50400",
),
),
"14" => array(
"start" => array(
0 => "36000",
),
"end" => array(
0 => "50400",
),
),
);
what I get instead:
$data= array(
"13" => array(
"start" => array(
0 => "36000",
),
"end" => array(
0 => "43200",
),
),
"14" => array(
"start" => array(
0 => "36000",
),
"end" => array(
0 => "43200",
),
),
);
What I intend to achieve with the above function is to combine the consecutive time slots and as it can be seen, the first matching start time in the end is $data[13]['start'][1] = 43200, which matches with the position ..['end'][0], so therefore I'm expecting the $pos returned to also be 0, but the $pos returned is 1 and the wrong element gets treated.
Problem in detail
The $data array is dynamic and will not always be this. Even though the matching $start_time value in "end" array can clearly be found at position 0, the $pos value returned is instead 1.
Have been struggling with this for quite some time now and am unable to find a fault, hope someone else will.
Best,
Alari
This is happening because of operator precedence. !== has more precedence over =. So, in your if statement $pos is effectively getting assigned the result of array_search($start_time, $area['end'], true) !== false which is 1.
Just change your if statement to this and it should work
if (($pos = array_search($start_time, $area['end'], true)) !== false) {
This should work :
PHP
foreach ($data as &$area) {
foreach ($area['start'] as $key => &$start_time) {
if (($pos = array_search($start_time, $area['end'], true) !== false)) {
$val = $area['end'][$key];
unset($area['start'][$key]);
unset($area['end'][$key]);
$area['end'][0] = $val;
}
}
}
You should try this code, it's simple and work in your case
foreach ( $data as &$item ){
ksort($item['start']);
ksort($item['end']);
if ( $item['start'][1] == $item['end'][0] ){
$item['end'][0] = $item['end'][1];
unset($item['end'][1]);
unset($item['start'][1]);
}
}

mongodb $nin not work in php

Current Code:
$doc = array('ooxx' => array(1,2,3,4,5));
datamodel()->insert($doc);
$doc2 = array('ooxx' => array(6,7,8,9));
datamodel()->insert($doc2);
$macher = array('ooxx'=>array('$exists' => true), 'ooxx' => array('$nin'=>array(6)));
$res = datamodel()->findOne($macher);
print_r($res);
When I replace the $macher with bellow, it does work well, why? is this a bug of mongodb?
$macher = array( 'ooxx' => array('$nin'=>array(6)), 'ooxx'=>array('$exists' => true));
It doesn't work because the keys have the same name and one overwrites the other. So the "keys" need to be unique.
If you have two conditions for the same key you use the $and operator which takes an array of arguments:
$matcher = array(
'$and' => array(
array( 'ooxx' => array( '$nin' => array(6) ) ),
array( 'ooxx' => array( '$exists' => true ) )
)
)
Or for the JSON minded:
{
"$and": [
{ "ooxx": { "$nin": [6] } },
{ "ooxx": { "$exists": true } }
]
}
Which is a valid structure where what you are writing is not.

Convert multidimensional array into XML

Please read the bolded line below before you comment that this may be a duplicate. This has nothing to do with SimpleXML.
Let me start off by showing how the XML should be laid out. Please ignore the namespaces:
<hot:SearchHotels>
<hot:request>
<hot1:Destination>?</hot1:Destination>
<hot1:HotelCityName>?</hot1:HotelCityName>
<hot1:HotelLocationName>?</hot1:HotelLocationName>
<hot1:HotelName>?</hot1:HotelName>
<hot1:CheckIn>?</hot1:CheckIn>
<hot1:CheckOut>?</hot1:CheckOut>
<hot1:RoomsInformation>
<!--Zero or more repetitions:-->
<hot1:RoomInfo>
<hot1:AdultNum>?</hot1:AdultNum>
<hot1:ChildNum>?</hot1:ChildNum>
<!--Optional:-->
<hot1:ChildAges>
<!--Zero or more repetitions:-->
<hot1:ChildAge age="?"/>
</hot1:ChildAges>
</hot1:RoomInfo>
</hot1:RoomsInformation>
<hot1:MaxPrice>?</hot1:MaxPrice>
<hot1:StarLevel>?</hot1:StarLevel>
<hot1:AvailableOnly>?</hot1:AvailableOnly>
<hot1:PropertyType>?</hot1:PropertyType>
<hot1:ExactDestination>?</hot1:ExactDestination>
</hot:request>
</hot:SearchHotels>
Notice under hot1:RoomsInformation there is RoomInfo. I'm supposed to be able to send multiple RoomInfo nodes. But I'm using a PHP class to convert an array to this object to be submitted via SOAP.
Here's my array before it gets converted to an object:
$param = array(
"Destination" => $destcode,
"HotelCityName" => $city,
"HotelLocationName" => "",
"HotelName" => "",
"CheckIn" => date("Y-m-d", strtotime($checkin)),
"CheckOut" => date("Y-m-d", strtotime($checkout)),
"RoomsInformation" => array (
"RoomInfo" => array(
"AdultNum" => 2,
"ChildNum" => 1,
"ChildAges" => array(
"ChildAge" => array(
"age"=>11
)
)
),
"RoomInfo" => array(
"AdultNum" => 1,
"ChildNum" => 0,
"ChildAges" => array(
"ChildAge" => array(
"age"=>0
)
)
)
),
"MaxPrice" => 0,
"StarLevel" => 0,
"AvailableOnly" => "false",
"PropertyType" => "NotSet",
"ExactDestination" => "false"
);
$param = arrayToObject($param) ;
$obj = new stdClass();
$obj->request=$param;
$result = $test->SearchHotels($obj) ;
The problem is that after converting to an Object, there is only 1 RoomInfo and its the last one. My thought is because the RoomsInformation array has 2 identical KEY names. So how can I make this work?
For your information, here is the SOAP class I use and the arrayToObject function:
http://pastebin.com/SBUN0FAF
The problem is, your array is invalid as you suspected because of the duplicate keys. One way to solve the issue is to wrap each "RoomInfo" in its own array like so:
$param = array(
"Destination" => $destcode,
"HotelCityName" => $city,
"HotelLocationName" => "",
"HotelName" => "",
"CheckIn" => date("Y-m-d", strtotime($checkin)),
"CheckOut" => date("Y-m-d", strtotime($checkout)),
"RoomsInformation" => array (
array(
"RoomInfo" => array(
"AdultNum" => 2,
"ChildNum" => 1,
"ChildAges" => array(
"ChildAge" => array(
"age"=>11
)
)
),
),
array(
"RoomInfo" => array(
"AdultNum" => 1,
"ChildNum" => 0,
"ChildAges" => array(
"ChildAge" => array(
"age"=>0
)
)
)
)
),
"MaxPrice" => 0,
"StarLevel" => 0,
"AvailableOnly" => "false",
"PropertyType" => "NotSet",
"ExactDestination" => "false"
);
And you can generate the XML like this:
// create simpleXML object
$xml = new SimpleXMLElement("<?xml version=\"1.0\"?><SearchHotels></SearchHotels>");
$node = $xml->addChild('request');
// function call to convert array to xml
array_to_xml($param, $node);
// display XML to screen
echo $xml->asXML();
die();
// function to convert an array to XML using SimpleXML
function array_to_xml($array, &$xml) {
foreach($array as $key => $value) {
if(is_array($value)) {
if(!is_numeric($key)){
$subnode = $xml->addChild("$key");
array_to_xml($value, $subnode);
} else {
array_to_xml($value, $xml);
}
} else {
$xml->addChild("$key","$value");
}
}
}
I attribute the array_to_xml function to the wonderful author here: https://stackoverflow.com/a/5965940/2200766
It looks as though you should have your array like this, instead;
$param = array(
"Destination" => $destcode,
"HotelCityName" => $city,
"HotelLocationName" => "",
"HotelName" => "",
"CheckIn" => date("Y-m-d", strtotime($checkin)),
"CheckOut" => date("Y-m-d", strtotime($checkout)),
"RoomsInformation" => array (
"RoomInfo" => array(
array(
"AdultNum" => 2,
"ChildNum" => 1,
"ChildAges" => array(
"ChildAge" => array(
"age"=>11
)
)
),
array(
"AdultNum" => 1,
"ChildNum" => 0,
"ChildAges" => array(
"ChildAge" => array(
"age"=>0
)
)
)
)
),
"MaxPrice" => 0,
"StarLevel" => 0,
"AvailableOnly" => "false",
"PropertyType" => "NotSet",
"ExactDestination" => "false"
);
This will preserve the two RoomInfo array elements.
simply use this function, where $data is multideminsional array
function array_to_xml( $data ) {
$xml_data = new SimpleXMLElement('<?xml version="1.0"?><data></data>');
foreach( $data as $key => $value ) {
$node = $xml_data->addChild('row_' . $key);
foreach( $value as $keyx => $valuex ) {
$node->addChild($keyx,$valuex);
}
}
return $xml_data->asXML();
}

Categories