laravel array groupBy specific column value - arrays

I'm working with arrays in laravel and I have a result like this:
$datesArr = [ {
"day": "monday",
"date": "2021-05-03"
},
{
"day": "monday",
"date": "2021-05-10"
},
{
"day": "monday",
"date": "2021-05-17"
}
]
what I want is this:
{
"day": "monday",
"dates" : [
{"date": "2021-05-03"},
{"date": "2021-05-10"},
{"date": "2021-05-17"},
]
}

Hope to help you (should convert all to array)
public static function buildArrayGroupBy($key, $data , $lockKey = null) {
$result = array();
foreach($data as $val) {
if(array_key_exists($key, $val)){
if(!is_null($lockKey)){
$result[$val[$key]][] = $val[$lockKey];
}else{
$result[$val[$key]][] = $val;
}
}else{
$result[""][] = $val;
}
}
return $result;
}

You can use Laravel Collection's groupBy function.
The output will be in the format below but it'll do the job.
$datesArr = [
"monday" => [
{
"day": "monday",
"date": "2021-05-03"
},
{
"day": "monday",
"date": "2021-05-10"
},
{
"day": "monday",
"date": "2021-05-17"
}
]
]
For exact output like mentioned, You can use mapToGroups.
$data->mapToGroups(function($i) {
return ['day' => $i['day'],
'dates' => [
'date' => $i['date']
]];
});
P.S: You might have to change it a little bit according to your requirements.

Thank you to all that tried to help me. I came with an idea how to solv it.
I will try to explain it here.
First I got all days that I have stored. then:
$daysArr = array();
foreach($days as $key => $day){
$datesArr = array();
for($i = 0;$i< 8;$i++){
$newDate['date'] = now()->next($key)->addWeeks($i)->toDateString();
array_push($datesArr,$newDate);
}
$test['day'] = $key;
$test['dates'] = $datesArr;
array_push($daysArr,$test);
unset($datesArr);
}
return $daysArr;
I did double array_push and foreach "new day" , I unset $datesArr to get empty array for pushing new dates of "new day".
Hope I was clear enough!

Let's generate some dummy data based on your requirements:
foreach(range(1,100) as $rangeTbs){
$carbon = \Carbon\Carbon::now()
->addDays(rand(1,20))
->addMonths(rand(1,2));
$dateArrayTbs[] = [
'day' => $carbon->format('l'),
'date' => $carbon->format('Y-m-d'),
];
}
Now we can convert array into collection:
$collection = collect($dateArrayTbs)
//Grouping By day
->groupBy('day')
//Now Converting into Desired Format
->map(function(Collection $collection,$day){
return [
'day' => $day,
'dates' => $collection->sortBy('date')->toArray(),
];
});

Related

Cakephp how can I fetch same table association data

I have a database table called miles, miles data looks like after fetch and return in Json.
"userMiles": [
{
"id": 278,
"gain_miles": 0.02,
"start_time": "2022-07-06T15:40:47+09:00",
"end_time": "2022-07-06T15:45:08+09:00",
},
{
"id": 279,
"gain_miles": 0.02,
"start_time": "2022-08-06T15:40:47+09:00",
"end_time": "2022-08-06T15:45:08+09:00",
},
]
I have written code to fetch data looks
$milesTable = TableRegistry::getTableLocator()->get( 'Miles' );
$query = $milesTable->find('all'));
try{
$userMiles = $this->paginate($query);
}
catch (NotFoundException $e){
$userMiles = [];
}
Now I'm trying to change this Json structure like below
"userMiles": [
{
"start_date": "06-July",
"miles":[
{
"id": 278,
"gain_miles": 0.02,
"start_time": "2022-07-06T15:40:47+09:00",
"end_time": "2022-07-06T15:45:08+09:00",
},
...
]
},
{
"start_date": "01-Mar",
"miles":[
{
"id": 281,
"gain_miles": 0.20,
"start_time": "2022-03-01T15:40:47+09:00",
"end_time": "2022-03-01T15:45:08+09:00",
},
...
]
},
]
For change Json Structure like above I have tried below codes , but don't know what is the procedure I will follow to get this output.
$query = $milesTable->find();
->select(["start_date" => "TO_CHAR(start_time,'DD-Mon')"])
->contain('Miles')
;
In `milesTable.php`
$this->hasMany('Miles',[
'foreignKey' => 'start_time',
'joinType' => 'LEFT',
]);
For this query getting error " "Unable to load Miles association. Ensure foreign key in Miles is selected."
My first query is Am I in right track ? Which procedure I can follow to get my desire output Json ?
I have tried by group by and order
$query = $milesTable
->find()
->select([
"start_date" => "TO_CHAR(start_time,'DD-Mon')",
"gain_miles",
"start_time",
"end_time",
])
->group(['start_date','id'])
->order(['start_time' => 'DESC'])
;
Output That I'm getting
"query": [
{
"start_date": "05-Jul",
"gain_miles": 400,
"start_time": "2022-07-05T14:14:23+06:00",
"end_time": "2022-07-06T14:14:23+06:00",
},
....
];
No if I use Collection
$collection = new Collection($query);
$miles = $collection->groupBy('start_date');
I'm getting my desire result, but problem is pagination, can I use pagination on collection $query data ? Or how can I implement pagination here ?
First you can select your group by start_date, then you can write a method in your Miles Entity. (Solution for postgresql)
$query = $this->paginate($milesTable
->find()
->select([
"start_date" => "TO_CHAR(start_time,'DD-Mon')",
])
->group(['start_date'])
);
then in your entity
public function _getMilesByStartTime()
{
return \Cake\ORM\TableRegistry::getTableLocator()->get('Miles')
->find()
->where([
"TO_CHAR(start_time,'DD-Mon') = '$this->start_date'"
]);
}
Now In controller
foreach ($query as $entity) {
$userMiles[] = [
'start_time' => $entity->start_date,
'miles' => $entity->milesByStartTime
];
}
$userMiles array should contain your data ! Have n't test but think it will help !

Laravel how to return object into JSON Arrays data type without keys

I have DB query in the Controller like this:
$query = User::all('id','name','email')->take(2);
$users = ["data" => $query];
return $users;
And get the result:
{
"data": [
{
"id": 1,
"name": "Peter",
"email": "peter#peter.com"
},
{
"id": 2,
"name": "John",
"email": "john#john.com"
}
]
}
But i'm expecting to get JSON Arrays data type without keys like this:
{
"data": [
[
"1",
"Peter",
"peter#peter.com"
],
[
"2",
"John",
"john#john.com"
]
]
}
I need to get this type for DataTables JSONP data source for remote domains.
https://datatables.net/examples/server_side/jsonp.html
How to do this?
Thanks.
You can try array_values like so:
$query = User::all('id', 'name', 'email')->take(2);
$users = ["data" => $query->map(function (User $user) {
return array_values($user->attributesToArray());
})];
return $users;
How about something like this?
$query = User::all('id', 'name', 'email')->take(2);
$userValues = $query->map(function($item, $key) {
return [
$item['id'],
$item['name'],
$item['email']
];
})
$users = ["data" => $userValues];
return $users;
// result
{
"data": [
[
1,
"Amy Wilderman",
"vrau#example.net",
],
[
2,
"Bria Lindgren PhD",
"trevor.armstrong#example.org",
],
]
}

How to parse field name using laravel

My Controller Code:
public function usersGroups(Request $request)
{
$resultArray = [];
$users = DB::table('users')
->join('user_basic_info','users.id','=','user_basic_info.user_id')
->select('users.id','user_basic_info.first_name')->get();
$resultArray['users'] = $users;
$groups = DB::table('group')
->select('group.id','group.name')->get();
$resultArray['groups'] = $groups;
return \Illuminate\Support\Facades\Response::json($resultArray, 200);
}
My Response:
{
"users": [
{
"id": 1,
"first_name": "Admin"
},
{
"id": 2,
"first_name": "Admin"
},
{
"id": 3,
"first_name": "Admin"
},
{
"id": 4,
"first_name": "Admin"
}
],
"groups": [
{
"id": 1,
"name": "Our Lira"
},
{
"id": 2,
"name": "CM"
}
]
}
here i there is field name first_name and i want to change it to name without changing the field name in table just for this API i want to change first_name to name.
How i can achieve this?
Your help needs here
You can simply make an alias using MySQL:
$users = DB::table('users')
->join('user_basic_info','users.id','=','user_basic_info.user_id')
->select('users.id','user_basic_info.first_name as name')->get();
Notice the as name in the select query.
Use an API Resource
These are classes that let you transform your models to whatever JSON format/layout you want.
i am not so good in api but you can achive it through setting alaias name
public function usersGroups(Request $request)
{
$resultArray = [];
$users = DB::table('users')
->join('user_basic_info','users.id','=','user_basic_info.user_id')
->select('users.id','user_basic_info.first_name as name')->get();
$resultArray['users'] = $users;
$groups = DB::table('group')
->select('group.id','group.name')->get();
$resultArray['groups'] = $groups;
return \Illuminate\Support\Facades\Response::json($resultArray, 200);
}
Can You try this if there is any error kindly comment below

How to modify a complex JSON Object in using Immutable

I have below JSON and wanted to update the value depending on Aid, Bid and Cid using Immutable.js
e.g.
Below input provided.
Aid= A, Bid = 1, Cid= 4, NewValue = 'FOUR'
If above input is provided the value "One" needs to be changed to "FOUR"
let sampleJson = {
Aid: 'A', detail:"sample", list: [
{
"Bid": "1",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "One"
},
{
"name": "Group A",
"Cid": "41",
"value": "1"
},
]
},
{
"Bid": "2",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
]
};
I was able to access the value using below code. How can i return the entire JSON with updated value?
let variale = Immutable.fromJS(sampleJson).
getIn(['list']).
find(allocation => allocation.get("Bid") === "1").
getIn(['group']).
find(fun => fun.get("Cid") === "4").set('value',"FOUR");
Anyone has any suggestions on how to resolve this problem?
I think you can try to do this like so:
let immutable = Immutable.fromJS(sampleJson);
immutable = immutable.setIn(['list', 0, 'group', 0, 'value'], 'FOUR');
This monstrosity is how I would do it:
const newData = originalData.update('list', list => {
const itemIndex = list.findIndex(item => item.get('Bid') === '2');
return list.update(itemIndex, listItem => {
return listItem.update('group', groupList => {
const groupIndex = list.findIndex(group => group.get('Cid') === '4');
return groupList.update(groupIndex, group => {
return group.set('value', 'FOUR');
});
});
});
});
https://jsbin.com/latupo/7/edit?html,js,console
Personally I stopped using Immutable, I always found it a bit painful (not to mention those docs!). I now use redux and good old cloning to not mutate state. Less performant in theory but if you've got nothing that runs over a few milliseconds anyway, save yourself the trouble...

Insert/Update/Push Array in existing Document in mongodb [duplicate]

I have a document like this:
_id: ObjectId("559c1d2ad8291bc9368b4568")
tablename: "IWEO_IWBB"
out_user: "pb"
out_email: "email"
out_date: "15.05.2015"
and want to add array like this:
"inventar": [
{
"ean": "2",
"name": "name2",
"runtime": "0",
"art": "null",
"marker": "null",
"stammkost": "null",
"accepted": "0"
},
{
"ean": "1",
"name": "name1",
"runtime": "0",
"art": "null",
"marker": "null",
"stammkost": "null",
"accepted": "0"
}
],
In my old PHP-Server I used the code below to insert it.
The right command is "update". In node.js it seems to be another command.
foreach($jArray as $value){
//$uuid = uniqid('', true);
$tablename = $value['tablename'];
$ean = $value["ean"];
$runtime = $value["runtime"];
$art = $value["art"];
$marker = $value["marker"];
$stammkost = $value["stammkost"];
$new_data = array(
//array (
'ean' => $ean,
'runtime' => $runtime,
'art' => $art,
'marker' => $marker,
'stammkost' => $stammkost,
'accepted' => '0'
//)
);
try {
$collection->update(array("tablename"=>$tablename),array('$push' => array("inventar" => $new_data)));
echo json_encode($collection);
}
catch ( MongoConnectionException $e ) {
echo '<p>Update failed</p>';
exit();
}
}
In my new node.js I use the code below:
tables.forEach(function(table) {
var tablename = table.tablename;
var name = table.name ;
var ean = table.ean;
var runtime= table.runtime;
var art = table.art;
var marker = table.marker;
var stammkost = table.stammkost;
console.log(tablename+" "+ean+" "+name+" "+runtime+" "+art+" "+marker+" "+stammkost);
OutAccept.update(function (err, data) {
if (err) console.log(err);
else {
console.log(data);
}
});
response.end();
//}
});
});
The output in console is:
IWEO_IWBB_01062015 1 name1 11337 A null null
{ ok: 0, n: 0, nModified: 0 }
IWEO_IWBB_01062015 2 name2 A null null
{ ok: 0, n: 0, nModified: 0 }
Why it isnt updated/inserted? Its the wrong command?
There are a few things wrong in your code here. First and foremost to note is that you are running in an "async" environment now and you need to change the thinking on how you do some things.
Your previous PHP code is "blocking", which means that every line of code must complete before moving on to the next line of code. This includes waiting for a database server to perform an update and return the response.
You cannot use basic control loops with functions inside them that perform asynchronously. Instead you need something that can call the next iteration of the loop (or at least signal that a single iteration is complete ) once the asynchronous function "update" has actually returned a result.
The second point here is that "nothing updated" because you did not tell the function what to update or what to update the matched document with.
The following is analogous to you original PHP listing, but adjusted for "async" methods also use the async.eachSeries for the loop control from the async library:
async.eachSeries(
tables,
function(table,callback) {
var tablename = table.tablename;
delete table.tablename; // just remove the key rather than re-construct
OutAccept.update(
{ "tablename": tablename },
{ "$push": { "inventar": table } },
function(err,numAffected) {
console.log( numAfftected ); // tells you how many are updated or nothing
callback(err)
}
);
},
function(err) {
// comes here on completion of all array items
}
);
The .findOneAndUpdate() command instead returns the document that was modified and with the modifications only if you ask for them with { "new": true }
async.eachSeries(
tables,
function(table,callback) {
var tablename = table.tablename;
delete table.tablename;
OutAccept.findOneAndUpdate(
{ "tablename": tablename },
{ "$push": { "inventar": table } },
{ "new": true },
function(err,doc) {
console.log( doc ); // shows the modified document
callback(err)
}
);
},
function(err) {
// comes here on completion of all array items
}
);
If you want to add Multiple array elements at once, or if you have even a single element directly in an array then use the $each modifier to $push:
var inventor = [
{
"ean": "2",
"name": "name2",
"runtime": "0",
"art": "null",
"marker": "null",
"stammkost": "null",
"accepted": "0"
},
{
"ean": "1",
"name": "name1",
"runtime": "0",
"art": "null",
"marker": "null",
"stammkost": "null",
"accepted": "0"
}
];
OutAccept.update(
{ "tablename": tablename },
{ "$push": { "inventar": { "$each": inventar } } },
function(err,numAffected) {
// work in here
}
);

Resources