I have one array with objects, and what I would like to achieve is to group the objects if a similar key already exists. What my JSON output looks like is,
[
{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
},
{
"id": 34,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "36"
},
{
"id": 26,
"slug": "green",
"stock": true,
"name": "Green",
"default": 0,
"sizes": "48"
}
What I would like to achieve is to group the similar slugs, and have an array of all the sizes in one. So something like this below,
[
{
"slug": "red",
"name": "Red",
"sizes" : [{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
},
{
"id": 34,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "36"
}]
}, {
"slug": "green",
"name": "Green",
"sizes": [{
"id": 26,
"slug": "green",
"stock": true,
"name": "Green",
"default": 0,
"sizes": "48"
}]
}
]
I'm not so much of a PHP guru, so been trying to figure out all day how to do this searching all over, and hoping someone fluent in PHP can help me out.
You can use one loop to group your result by slug first and then use another to get what you want. Let's try like this way-
<?php
$json = '[{"id":37,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"38"},{"id":38,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"40"},{"id":34,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"36"},{"id":26,"slug":"green","stock":true,"name":"Green","default":0,"sizes":"48"}]';
$array = json_decode($json,1);
$expected = [];
foreach($array as $v) {
$expected[$v['slug']][] = $v;
}
$expected_v2 = [];
foreach($expected as $k1=>$v1) {
array_push($expected_v2,['slug'=>$k1,'name'=>ucfirst($k1),'sizes'=>$v1]);
}
//print_r($expected_v2);
echo json_encode($expected_v2);
?>
Output:
[{"slug":"red","name":"Red","sizes":[{"id":37,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"38"},{"id":38,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"40"},{"id":34,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"36"}]},{"slug":"green","name":"Green","sizes":[{"id":26,"slug":"green","stock":true,"name":"Green","default":0,"sizes":"48"}]}]
DEMO: https://3v4l.org/WfbsX
You can use `array_reduce to achieve this :
$json = '[{"id":37,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"38"},{"id":38,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"40"},{"id":34,"slug":"red","stock":true,"name":"Red","default":0,"sizes":"36"},{"id":26,"slug":"green","stock":true,"name":"Green","default":0,"sizes":"48"}]';
$input = json_decode($json, true);
$output = array_reduce(array_reduce($input, function ($carry, $item) {
$carry[$item['slug']][] = $item;
return $carry;
}, []), function ($carry, $group) {
$carry[] = [
'slug' => $group[0]['slug'],
'name' => $group[0]['name'],
'sizes' => $group
];
return $carry;
}, []);
Related
I want to order my products like this, get all products, group them by color, and get first three color with most item.
$products = Products::select('color', DB::raw('count(*) as total'))
->groupBy('color')
->orderBy('total', 'desc')
->limit(3)
->get();
but it only gives me something like this:
[
{
"color": "red",
"total": 3
},
{
"color": "blue",
"total": 2
},
{
"color": "yellow",
"total": 1
}
]
with no total, It gives me all rows grouped by color, but I want to get all rows grouped by color and order them with total.
something like this order by each total:
(red color comes, then blue and yellow)
{
"red": [
{
"id": 1,
"title": "first red product",
"color": "red",
"created_at": "2022-09-03T23:44:59.000000Z",
"updated_at": "2022-09-03T23:44:59.000000Z"
},
{
"id": 3,
"title": "second red product",
"color": "red",
"created_at": "2022-09-03T23:45:40.000000Z",
"updated_at": "2022-09-03T23:45:40.000000Z"
},
{
"id": 6,
"title": "some red product",
"color": "red",
"created_at": "2022-09-03T23:44:59.000000Z",
"updated_at": "2022-09-03T23:44:59.000000Z"
}
],
"blue": [
{
"id": 2,
"title": "some blue product",
"color": "blue",
"created_at": "2022-09-03T23:45:40.000000Z",
"updated_at": "2022-09-03T23:45:40.000000Z"
},
{
"id": 4,
"title": "another blue product",
"color": "blue",
"created_at": "2022-09-03T23:45:40.000000Z",
"updated_at": "2022-09-03T23:45:40.000000Z"
}
],
"yellow": [
{
"id": 5,
"title": "some yellow product",
"color": "yellow",
"created_at": "2022-09-03T23:45:40.000000Z",
"updated_at": "2022-09-03T23:45:40.000000Z"
}
]
}
You can use collection method: groupBy sortBy count map take all
$products = Products::all()
->groupBy('color')
->sortBy(fn ($groupValue, $groupKey) => count($groupValue), SORT_REGULAR, true)
->map(fn($groupValue, $groupKey) => $groupValue->take(3))
->all();
So I'm having a strange problem with Doctrine that I don't understand and need help with. Essentially, I am running quite a complex query due to the nature of my database and its various joins and for some reason the response when I grab try to grab all records from my database is returning my entities incorrectly.
See my doctrine query below:
$subQuery = $this->_em->createQueryBuilder()
->from(Product::class, 'ex')
->select('ppsi.id')
->join('ex.productSpecificationItems', 'ppsi')
->where('ex.id = p.id');
$subQuery = $subQuery->getDQL();
$subQuery2 = $this->_em->createQueryBuilder()
->from(Product::class, 'ex2')
->select('ppoiv.id')
->join('ex2.productOptionItemValues', 'ppoiv')
->where('ex2.id = p.id');
$subQuery2 = $subQuery2->getDQL();
$subQuery3 = $this->_em->createQueryBuilder()
->from(Product::class, 'ex3')
->select('poie.id')
->join('ex3.productOptionItems', 'poie')
->where('ex3.id = p.id');
$subQuery3 = $subQuery3->getDQL();
$qb = $this->createQueryBuilder('p')
->select('p, pc, psc, i, po, poi, poiv, ps, psi')
->join('p.productCategory', 'pc')
->leftJoin('p.productSubCategory', 'psc')
->leftJoin('p.images', 'i')
->leftJoin('p.productOptions', 'po')
->leftJoin('p.productSpecifications', 'ps')
->leftJoin('ps.productSpecificationItems', 'psi', Join::WITH, 'psi.id IN (' . $subQuery. ')')
->leftJoin('po.productOptionItems', 'poi', Join::WITH, 'poi.id IN (' . $subQuery3. ')')
->leftJoin('poi.productOptionItemValue', 'poiv', Join::WITH, 'poiv.id IN (' . $subQuery2. ')')
->addOrderBy('p.id', 'ASC');
The response of this causes some entities to have the productOptionItemValues either listed under the wrong productOptionItem, just causes blank records to return, or doesn't return them at all. See an example below (as a JSON for clarity):
{
"id": 373,
"name": "test",
"code": "test",
"url": "373-test",
"price": "1.00",
"stock": 1,
"description": "<p>fghfgh mnsdbfksdhfjk sd</p>\n",
"live": false,
"createdAt": "2022-03-17T14:45:35+00:00",
"updatedAt": "2022-03-17T15:12:44+00:00",
"featured": false,
"aggregateReviewScore": null,
"productCategory": {
"id": 2,
"name": "Hex Set Screws",
"url": "hex-set-screws"
},
"productSubCategory": {
"id": 12,
"name": "Nylon",
"url": "nylon"
},
"images": [],
"productOptions": [
{
"id": 1,
"name": "Colour",
"productOptionItems": {
"0": {
"id": 2,
"name": "Black",
"productOptionItemValue": [
{
"id": 1196,
"stock": 1,
"price": "1.00",
"useOwn": false
},
{
"id": 1201,
"stock": 1,
"price": "1.00",
"useOwn": false
},
{
"id": 1198,
"stock": 1,
"price": "1.00",
"useOwn": false
}
]
},
"1": {
"id": 8,
"name": "Yellow",
"productOptionItemValue": [
{
"id": 1197,
"stock": 1,
"price": "1.00",
"useOwn": false
}
]
},
"2": {
"id": 14,
"name": "Light Grey"
},
"3": null,
"4": {
"id": 15,
"name": "Mid Grey"
},
"7": null,
"8": {
"id": 20,
"name": "Light Blue"
},
"11": null,
"12": {
"id": 22,
"name": "Purple"
},
"13": null
}
},
{
"id": 2,
"name": "Pack Size",
"productOptionItems": [
{
"id": 3,
"name": "10",
"productOptionItemValue": [
{
"id": 1180,
"stock": 100,
"price": "10.00",
"useOwn": true
}
]
},
{
"id": 4,
"name": "100",
"productOptionItemValue": [
{
"id": 1181,
"stock": 10,
"price": "1000.00",
"useOwn": true
}
]
}
]
}
],
"productSpecifications": []
}
If I run the same query on a SINGLE product (so the same Doctrine Query as a above just with a p.id = :id WHERE added) it returns absolutely fine. See the response for that below (and the CORRECT response I am looking for):
{
"id": 373,
"name": "test",
"code": "test",
"url": "373-test",
"price": 1,
"stock": 1,
"description": "<p>fghfgh mnsdbfksdhfjk sd</p>\n",
"live": false,
"createdAt": "2022-03-17T14:45:35+00:00",
"updatedAt": "2022-03-17T15:12:44+00:00",
"featured": false,
"aggregateReviewScore": null,
"productCategory": {
"id": 2,
"name": "Hex Set Screws",
"url": "hex-set-screws"
},
"productSubCategory": {
"id": 12,
"name": "Nylon",
"url": "nylon"
},
"images": [],
"productOptions": [
{
"id": 1,
"name": "Colour",
"productOptionItems": [
{
"id": 2,
"name": "Black",
"productOptionItemValue": {
"id": 1196,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 7,
"name": "Red",
"productOptionItemValue": {
"id": 1201,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 8,
"name": "Yellow",
"productOptionItemValue": {
"id": 1197,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 14,
"name": "Light Grey",
"productOptionItemValue": {
"id": 1202,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 15,
"name": "Mid Grey",
"productOptionItemValue": {
"id": 1205,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 20,
"name": "Light Blue",
"productOptionItemValue": {
"id": 1203,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 22,
"name": "Purple",
"productOptionItemValue": {
"id": 1204,
"stock": 1,
"price": 1,
"useOwn": false
}
},
{
"id": 23,
"name": "Natural",
"productOptionItemValue": {
"id": 1198,
"stock": 1,
"price": 1,
"useOwn": false
}
}
]
},
{
"id": 2,
"name": "Pack Size",
"productOptionItems": [
{
"id": 3,
"name": "10",
"productOptionItemValue": {
"id": 1180,
"stock": 100,
"price": 10,
"useOwn": true
}
},
{
"id": 4,
"name": "100",
"productOptionItemValue": {
"id": 1181,
"stock": 10,
"price": 1000,
"useOwn": true
}
}
]
}
],
"productSpecifications": []
}
Any help or ideas would be greatly appreciated!
let say, i have this JSON data i want to print all key by name "id", what should i do?
$json = {"response":[
{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
}
]}
i tried this but this one is only giving me first array object sub key(which is id=37) i want all like (id=37, id=38)
$op = $json->{'response'}[0]->{'id'};
If I assume your JSON is really JSON, and therefore a string, you could do this:
$json = '{"response":[
{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
}
]}';
$data = json_decode($json);
$ids = array_column($data->response, 'id');
print_r($ids);
This would result in:
Array
(
[0] => 37
[1] => 38
)
See a PHP Fiddle.
You can turn the JSON string into a usable PHP data with json_decode().
The way to get the id's is by using array_column().
You can loop over your response
$array = [];
foreach ($json->{'response'} as $reponseItem){
$array[$reponseItem['id']] = $reponseItem;
}
You need to decode your json string into array 1st and then loop through data.
$json = ' {"response":[
{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
}
]}';
$jsonArray =json_decode($json,true); //convert your json string to array.
$newJson = $jsonArray ['response'];
foreach($newJson as $data)
{
echo $data['id'];
}
OR You can directly loop through your $jsonArray['response'].
foreach($jsonArray['response'] as $data)
{
echo $data['id'];
}
$json = '{"response":[
{
"id": 37,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "38"
},
{
"id": 38,
"slug": "red",
"stock": true,
"name": "Red",
"default": 0,
"sizes": "40"
}
]}';
$data = json_decode($json); // we decode the JSON
$num = count($data->response); // we count how many response keys we have
$i=0; // define $1=0 to start our iteration
while ($i < $num) { // $i must be < than the counted array keys
$op = $data->response[$i]->id; // we tell the while loop to iterate over the array
print $op."</br>"; // prints out 37 & 38
$i++; // Standard incrementation
}
Let's consider the following JSON response. It is a list of station objects.
[
{
"id": 43,
"trucks": [
{
"id": 24,
"vehicleType": {
"id": 2,
"vehicleType": "VT",
"createdAt": 1622645476000,
"updatedAt": 1622645476000
},
"sensor": {
"id": 16,
"devId": "tutorial",
"readings": [
{
"id": 36296,
"interiorTemperature": 528.36,
"batteryTemperature": 528.36,
"batteryVoltage": 0,
"createdAt": 1623065279000,
"updatedAt": 1623065279000
}
],
"resolved": false,
"createdAt": 1622645598000,
"updatedAt": 1622650553000
},
"vehicleNumber": 123456,
"truckStatus": true,
"defaultBatteryVoltage": "12",
"batteryTempThreshold": 25,
"interiorTempThresholdMax": 30,
"interiorTempThresholdMin": 5,
"batteryVoltageThreshold": 11.5,
"createdAt": 1622645517000,
"updatedAt": 1622645663000
},
{
"id": 29,
"vehicleType": {
"id": 2,
"vehicleType": "VT",
"createdAt": 1622645476000,
"updatedAt": 1622645476000
},
"sensor": {
"id": 23,
"devId": "value",
"readings": [
{
"id": 36298,
"interiorTemperature": 10,
"batteryTemperature": 10,
"batteryVoltage": 10,
"createdAt": 1623074142000,
"updatedAt": 1623074142000
}
],
"resolved": false,
"createdAt": 1623074089000,
"updatedAt": 1623074089000
},
"vehicleNumber": 313215,
"truckStatus": true,
"defaultBatteryVoltage": "12",
"batteryTempThreshold": 50,
"interiorTempThresholdMax": 50,
"interiorTempThresholdMin": 50,
"batteryVoltageThreshold": 50,
"createdAt": 1623073365000,
"updatedAt": 1623073365000
}
],
"name": "value",
"city": "value",
"address": "value",
"zipCode": "value",
"createdAt": 1622645352000,
"updatedAt": 1622645352000
},
{
"id": 44,
"trucks": [
{
"id": 25,
"vehicleType": {
"id": 3,
"vehicleType": "AG",
"createdAt": 1622647436000,
"updatedAt": 1622647436000
},
"sensor": {
"id": 18,
"devId": "test",
"readings": [
null
],
"resolved": false,
"createdAt": 1622795394000,
"updatedAt": 1622795394000
},
"vehicleNumber": 123457,
"truckStatus": true,
"defaultBatteryVoltage": "24",
"batteryTempThreshold": 80,
"interiorTempThresholdMax": 50,
"interiorTempThresholdMin": -20,
"batteryVoltageThreshold": 11.5,
"createdAt": 1622645584000,
"updatedAt": 1623074846000
}
],
"name": "value",
"city": "value",
"address": "value",
"zipCode": "11112",
"createdAt": 1622645431000,
"updatedAt": 1622645431000
},
{
"id": 46,
"trucks": [
{
"id": 26,
"vehicleType": {
"id": 2,
"vehicleType": "VT",
"createdAt": 1622645476000,
"updatedAt": 1622645476000
},
"sensor": null,
"vehicleNumber": 979787,
"truckStatus": true,
"defaultBatteryVoltage": "12",
"batteryTempThreshold": 123,
"interiorTempThresholdMax": 123,
"interiorTempThresholdMin": 123,
"batteryVoltageThreshold": 123,
"createdAt": 1623064671000,
"updatedAt": 1623064671000
}
],
"name": "value",
"city": "value",
"address": "value",
"zipCode": "11111",
"createdAt": 1622918304000,
"updatedAt": 1622918304000
}
]
All stations have an id, a list of trucks, and some basic info (name, location etc). With PHP, I convert this to an array object. What I would like to achieve is to sort the array. Now I have managed to sort based on name or location. I used the following snipped:
usort($stations, function($a, $b) {
$retval = $a['name'] <=> $b['name'];
return $retval;
});
Now it's all nice but we would like to sort it based on the highest interior temperature read in a station. To make the station with the highest interior temperature be the 0th element in the list and the one with the lowest (or no reading at all) is the nth. I have tried playing around with usort but I had no results. Is it even possible to sort it like that?
Given an array, in which each index there are certain key value pairs, how do I select certain key value pairs and reject the others.
$channels = Channel::get()->toArray();
This will yield the following Array:
"channels": [
{
"id": 1,
"name": "Info Release",
"slug": "info-release",
"desc": "Contains blah blah.",
"access_level": "0",
"created_at": "2018-12-02 01:23:50",
"updated_at": "2018-12-05 07:54:41"
},
{
"id": 11,
"name": "Casual News",
"slug": "casual-news",
"desc": "Contains blah blah.",
"access_level": "0",
"created_at": "2018-12-05 05:34:50",
"updated_at": "2018-12-05 07:54:32"
},
{
"id": 12,
"name": "haha",
"slug": "haha",
"desc": "Contains blah blah.",
"access_level": "0",
"created_at": "2018-12-29 23:27:16",
"updated_at": "2018-12-29 23:27:16"
}
],
What is the best way to turn that array into this:
"channels": [
{
"id": 1,
"name": "Information Release",
"slug": "information-release",
},
{
"id": 11,
"name": "Casual News",
"slug": "casual-news",
},
{
"id": 12,
"name": "haha",
"slug": "haha",
}
],
So that if I write
$channels[0]->id
it will spit out 1
Can You try this
$viewFileds = ['id', 'name', 'slug'];
$channels = Channel::get()
->map(function ($each) use ($viewFileds) {
return Arr::only($each, $viewFileds);
});
It will return the new Collection by Only the field enabled in the $viewFileds
Hope it helps