In laravel am using eloquent to get data from the database.
I have two tables 'questions' and 'options'
Am using the eloquent method to join 'options' to 'questions'
$questions = Question::join('options', 'options.question_id', 'questions.id');
return QuestionResource($questions);
This does return an expected collection of data, where the same question appear multiple times in the collection and each is joined with different options where the 'options.question_id' and 'question.id' are the same.
[
{
id: 1,
text: "Africa is a...?",
// joined option
question_id: 1,
value: "city",
answer: false
},
{
id: 1,
text: "Africa is a...?",
// joined option
question_id: 1,
value: "planet",
answer: false
},
{
id: 1,
text: "Africa is a...?",
// joined option
question_id: 1,
value: "continent",
answer: true
},
{
id: 2,
text: "Albert Heinstein was a...?",
// joined option
question_id: 2,
value: "comedian",
answer: false
},
{
id: 2,
text: "Albert Heinstein was a...?",
// joined option
question_id: 1,
value: "genius scientist",
answer: true
}
]
I want all options be nested under a key within the related question. Like
[
{
id: 1,
text: "Africa is a...?",
// joined options
options: [
{value: "city", answer: false},
{value: "planet", answer: false},
{value: "continent", answer: true}
]
},
{
id: 2,
text: "Albert Heinstein was a...?",
// joined options
options: [
{value: "comedian", answer: false},
{value: "genius scientist", answer: true}
]
}
]
Can I achieve this with laravel's eloquent or I'll have to apply an extra logic.
If you want to applie extra logic this code may help you
<?php
$combinedqst = array('id' => '','text'=> '','option'=> array('value' => array('value' => ,'' ), 'answer' => ''));
$ids = array('id' => , '');
//loop through questions array 1st loop for getting the question
foreach($questions as $question) {
$count = 0;
//check if question is already looped
if(!in_array($question["id"],$ids)){
//2end loop to get the opstions
foreach($questions as $question_check) {
if($question_check["id"] == $question["id"]){
if($count == 0){
$combinedqst["id"] = $question["id"];
$combinedqst["text"] = $question["text"];
}
$count = 1;
array_push($combinedqst["option"]['value'],$question_check['value']);
array_push($combinedqst["option"]['answer'],$question_check['answer']);
}
}
}
array_push($ids,$question["id"]);
}
vardump($combinedqst);
Related
i have 2 objects that i use merge on them like below :
$data = $city->merge($accommodation);
return AccCitySearchResource::collection($data);
and in my resource
return [
'id' => $this->id,
'name' => $this->name,
'english_name' => $this->english_name,
'accommodation_type_id' =>$this->accommodation_type_id,
'grade_stars' =>$this->grade_stars,
'hits' =>$this->hits,
'accommodation_count' => $this->accommodation_count,
];
now all i want is that my $data first shows all cities and then shows all accommodations but now it shows all together is there any way to sort them ??
EDIT
This is what i get now
{
id: 5,
name: "hotel",
accommodation_type_id: 1,
grade_stars: 4,
hits: 22,
accommodation_count: null
},
{
id: 7,
name: "city",
accommodation_type_id: null,
grade_stars: null,
hits: null,
accommodation_count: 0
},
{
id: 10,
name: "hotel",
accommodation_type_id: 1,
grade_stars: 2,
hits: 0,
accommodation_count: null
},
And this is what i want
{
id: 5,
name: "hotel",
accommodation_type_id: 1,
grade_stars: 4,
hits: 22,
accommodation_count: null
},
{
id: 10,
name: "hotel",
accommodation_type_id: 1,
grade_stars: 2,
hits: 0,
accommodation_count: null
},
{
id: 7,
name: "city",
accommodation_type_id: null,
grade_stars: null,
hits: null,
accommodation_count: 0
},
just to mention as you see all hotels comes first and then all cities come .
The recommended way in the documentation is to create your own resource collection if you need to customise the default behavior:
php artisan make:resource AccCitySearchCollection
Then you can customise your collection:
class AccCitySearchCollection{
public function toArray($request)
{
return [
'data' => $this->collection->sortBy('name')
];
}
}
You can then return a collection instance:
$data = $city->merge($accommodation);
return new AccCitySearchCollection($data);
You can use sortBy Collection method
Created Resource Collection for model.
Then in toArray method write:
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'data' => $this->collection->sortByDesc(function($d){
return (int) ($d['name'] == 'hotel');
}),
];
}
This will sort your data as you want.
Hope this answer helps you
Maybe something like this ... But if you are getting your data from a database , maybe you could join and order the query instead..
$data = $city->merge($accommodation)->sortByDesc('some field of first object here');
i have a page called "grapghhehe" and in that page i have a bar chart and a form for user to select 2 dates(from and to) so when user selects this 2 dates it suppose to show the graph details based on the dates only.. so what i have done where it will return the data which is correct in an array like:
array:3 [
0 => 1
1 => 17
2 => 1
]
array:1 [
0 => 3
]
array:4 [
0 => 1
1 => 2
2 => 1
3 => 1
]
so as you can they are 3 arrays for 3 different values... now i want to return this data on the same page. how can i do that? my code so far:
public function graphheheByDate(Request $request, $companyID)
{
$companyID = $this->decode($companyID);
$match = DiraChatLog::where('status','=','Match')->where('date_access', '>=', $request->from)->where('date_access', '<=', $request->to)
->selectRaw('DATE(date_access) as date, COUNT(1) as cnt') // created_at here is datetime format, only need the date portion using `DATE` function
->orderBy("date")
->groupBy("date")
->get() // return result set (collection) from query builder
->pluck('cnt') // only need the cnt column
->values() // array_values
->sum(); // convert collection to array
$missing = DiraChatLog::where('status','=','Missing')->where('date_access', '>=', $request->from)->where('date_access', '<=', $request->to)
->selectRaw('DATE(date_access) as date, COUNT(1) as cnt') // created_at here is datetime format, only need the date portion using `DATE` function
->orderBy("date")
->groupBy("date")
->get() // return result set (collection) from query builder
->pluck('cnt') // only need the cnt column
->values() // array_values
->sum(); // convert collection to array
$noAnswer = DiraChatLog::where('status','=','No Answer')->where('date_access', '>=', $request->from)->where('date_access', '<=', $request->to)
->selectRaw('DATE(date_access) as date, COUNT(1) as cnt') // created_at here is datetime format, only need the date portion using `DATE` function
->orderBy("date")
->groupBy("date")
->get() // return result set (collection) from query builder
->pluck('cnt') // only need the cnt column
->values() // array_values
->sum(); // convert collection to array
$match = array(0 => $match);
$missing = array(0 => $missing);
$noAnswer = array(0 => $noAnswer);
// dd($match,$missing,$noAnswer);
$from = $request->from;
$to = $request->to;
// dd($from, $to);
$companyID = $this->encodeID($companyID);
return view('AltHr.Chatbot.graphhehe', compact('companyID','from','to'))->with('match',json_encode($match,JSON_NUMERIC_CHECK))->with('missing',json_encode($missing,JSON_NUMERIC_CHECK))->with('noAnswer',json_encode($noAnswer,JSON_NUMERIC_CHECK));
}
in this function when i dd the 3 values are correct details. i only want this data to bring to the same page to change the graph.
my graph javascript is as below:
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script type="text/javascript">
var match = <?php echo $match; ?>;
var missing = <?php echo $missing; ?>;
var noAnswer = <?php echo $noAnswer; ?>;
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Unique Visitors'
},
subtitle: {
text: ''
},
xAxis: {
categories: [
'Dates'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Total'
}
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
tooltip: {
headerFormat: '<span>{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y}</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'Match',
data: [match]
}, {
name: 'Missing',
data: [missing]
}, {
name: 'No Answer',
data: [noAnswer]
}]
});
</script>
I would like to create a flot bar graph based on a php output. I managed to output data from php, but I would also like to use labels and display them on the xaxis. For some reason the output of the code below is invalid. The labels show up, but the bars and xaxis labels do not.
PHP:
function getOverview() {
$arr[] = array(
'label' => "Label 1",
'data' => array(0, 1)
);
$arr[] = array(
'label' => "Label 2",
'data' => array(1, 2)
);
echo json_encode($arr);
}
Output:
[{"label":"Label 1","data":[0,1]},{"label":"Label 2","data":[1,2]}]
jQuery:
$(document).ready(function(){
$.ajax({
url: 'http://localhost/getOverview.php',
method: 'GET',
dataType:"json",
success: onOutboundReveived
});
function onOutboundReveived(series)
{
var options = {
series: {
bars: {
show: true,
barWidth: .1,
align: 'center'
}
},
xaxis: {
tickSize: 1
}
};
$.plot("#chart_filled_blue", series, options);
}
});
Can anyone help me?
You've got a couple problems:
1.) Series data needs to be an array of arrays. Not just a single array:
'data' => array(array(1, 2))
This is, of course, so a series could have more than one point (even though your's has a single point).
2.) To get xaxis labels, you have two options. One, use the categories plugin. Two, manually provide the tick labels:
ticks: [[0, "zero"], [1.2, "one mark"], [2.4, "two marks"]]
In your situation I'd just use the category plugin. You'll need to modify the final data to:
{"label":"Label 1","data":[["Label 1",1]]}
or in the PHP:
$arr[] = array(
'label' => "Label 1",
'data' => array(array("Label 1", 1))
);
Here's a fiddle.
I think, your output has an incorrect format. Try this:
[
{
label: "Label 1",
data: [[0,1]]
},
{
label: "Label 2",
data: [[1,2]]
}
]
I've been trying to learn how to convert MySQL query results to JSON arrays in PHP and I haven't managed to make much progress.
Basically I'm trying to convert the results of this query into an array:
$sql = mysql_query("SELECT `status` FROM jobs");
while($row = mysql_fetch_array($sql)){
$job_status = $row['status'];
}
Into this:
$data = array(
array( 'label'=> "a", 'data'=> 1), // The data values are queried using PHP and SQL
array( 'label'=> "b", 'data'=> 2),
array( 'label'=> "c", 'data'=> 3)
);
echo json_encode($data);
The $data array will be used display the values in the float chart. The code is shown below:
if($("#piechart").length)
{
$.plot($("#piechart"), data,
{
series: {
pie: {
show: true
}
},
grid: {
hoverable: true,
clickable: true
},
legend: {
show: false
},
colors: ["#FA5833", "#2FABE9", "#FABB3D", "#78CD51"]
});
Below is the JS code that is converted into a PHP array and the encoded using JSON.
var data = [
{ label: "a", data: 1},
{ label: "b", data: 2},
{ label: "c", data: 3},
Any help would be greatly appreciated!
mysql_fetch_assoc might work better
I need to update multiple embedded docs in mongo using PHP. My layout looks like this:
{
_id: id,
visits : {
visitID: 12
categories: [{
catagory_id: 1,
name: somename,
count: 11,
duration: 122
},
{
catagory_id: 1,
name: some other name,
count: 11,
duration: 122
},
{
catagory_id: 2,
name: yet another name,
count: 11,
duration: 122
}]
}
}
The document can have more than one visit too.
Now i want to update 2 categories, one with id=1 and name=somename and the other with id=1 and name=some_new_name. Both of them should inc "count" by 1 and "duration" by 45.
First document exists, but second does not.
Im thinking of having a function like this:
function updateCategory($id, $visitID,$category_name,$category_id) {
$this->profiles->update(
array(
'_id' => $id,
'visits.visitID' => $visitID,
'visits.categories.name' => $category_name,
'visits.categories.id' => $category_id,
),
array(
'$inc' => array(
'visits.categories.$.count' => 1,
'visits.categories.$.duration' =>45,
),
),
array("upsert" => true)
);
}
But with this i need to call the function for each category i will update. Is there any way to do this in one call?
EDIT:
Changed the layout a bit and made "categories" an object instead of array. Then used a combination of "category_id" and "category_name" as property name. Like:
categories: {
1_somename : {
count: 11,
duration: 122
},
1_some other name : {
count: 11,
duration: 122
},
2_yet another name : {
count: 11,
duration: 122
},
}
Then with upsert and something like
$inc: {
"visits.$.categories.1_somename.d": 100,
"visits.$.categories.2_yet another name.c": 1
}
i can update several "objects" at a time..
Mongodb currently not supporting arrays multiple levels deep updating (jira)
So following code will not work:
'$inc' => array(
'visits.categories.$.count' => 1,
'visits.categories.$.duration' => 123,
),
So there is some solutions around this:
1.Load document => update => save (possible concurrency issues)
2.Reorganize your documents structure like this(and update using one positional operator):
{
_id: id,
visits : [{
visitID: 12
}],
categories: [{
catagory_id: 1,
name: somename,
count: 11,
duration: 122,
visitID: 12
}]
}
}
3.Wait for multiple positional operators support (planning in 2.1 version of mongodb).
4.Reorganize your documents structure somehow else, in order to avoid multiple level arrays nesting.