How can I add muti-dimensional array to laravel database - php

I want to store product option on my database and loop through it when I retrieve the data. The data structure takes a form
[
{
"color": "black",
"extralCost": 100,
"size": {
"xs": 1,
"sm": 4,
"L": 2,
"XL":6
},
"stock":13
}, {
"color": "white",
"extralCost": 0,
"size": {
"xs": 1,
"sm": 4,
"L": 2
},
"stock":7
},
...
]
I want to be able to store this in the database and retrieve it at the view.

Add this to your Model.
protected $casts = [
'column_name' => 'array',
];
To get an array:
$request->except('_token', '_method')

Related

Group by an item in a nested array using laravel collection

I have an array that has the variable name $array and it is as follows:
$array = [
"data"=> [
[
"company"=>[
"id"=> 1,
"name"=> "company1"
],
"reports"=> [
"active_reports"=> 3,
"completed_reports"=> 2
]
],
[
"company"=>[
"id"=> 2,
"name"=> "company2"
],
"reports"=> [
"active_reports"=> 6,
"completed_reports"=> 1
]
],
[
"company"=>[
"id"=> 2,
"name"=> "company2"
],
"reports"=> [
"active_reports"=> 7,
"completed_reports"=> 5
]
]
]
];
So, I want to group this array by the company id. The id can be found in the nested array with key company
My expected result is below:
{
"1": [
{
"company": {
"id": 1,
"name": "company1"
},
"reports": {
"active_reports": 3,
"completed_reports": 2
}
}
],
"2": [
{
"company": {
"id": 2,
"name": "company2"
},
"reports": {
"active_reports": 6,
"completed_reports": 1
}
},
{
"company": {
"id": 2,
"name": "company2"
},
"reports": {
"active_reports": 7,
"completed_reports": 5
}
}
]
}
So, I tried the following logic:
foreach ($array['data'] as $data) {
$reportsData = collect($data)->groupBy($data['company']['id']);
Log::info($reportsData);
}
But this is the result I'm getting after trying the above logic:
[
{
"": [
{
"id": 1,
"name": "company1"
},
{
"active_reports": 3,
"completed_reports": 2
}
]
},
{
"": [
{
"id": 2,
"name": "company2"
},
{
"active_reports": 6,
"completed_reports": 1
}
]
},
{
"": [
{
"id": 2,
"name": "company2"
},
{
"active_reports": 7,
"completed_reports": 5
}
]
}
]
I want to be able to get the expected result as illustrated above.
You are passing a value to groupBy currently not a 'column' to group by. Though you have nested data here so you will need to pass a callback to groupBy where you will return what value the entities should be grouped by:
collect($array['data'])
->groupBy(fn ($item) => $item['company']['id']);
Or simply using the 'dot' notation (as mentioned by Donkarnash), since we are starting the collection at the 'data' key:
collect($array['data'])->groupBy('company.id');
Laravel 9.x Docs - Collections - Available Methods - groupBy

Add Timestamp while insertMany() in mongoDB

Hi I am MySQL user and new to mongoDB.
I get data from my IOT devices as following:
$body={
"key": "121239",
"secrete": "Your_Device_Secrete",
"data": [
{
"Temperature":50,
"Humidity":30,
"Vibration":100,
"Time":"2020-1-26 00:00:01"
},
{
"Temperature":55,
"Humidity":34,
"Vibration":50,
"Time":"2020-1-26 00:00:02"
}
]
}
I am inserting it into mongoDB using PHP CodeIgnitor as following:
$this->mongo->batch_insert($body["key"],$body["data"]);
data is getting inserted in collection named as given key as following:
{
"Temperature": 50,
"Humidity": 30,
"Vibration": 100,
"Time": "2020-1-26 00:00:01",
"_id": {
"$id": "5e330be3f7577f640d2a0922"
}
},
{
"Temperature": 55,
"Humidity": 34,
"Vibration": 50,
"Time": "2020-1-26 00:00:02",
"_id": {
"$id": "5e330be3f7577f640d2a0923"
}
}
Now I want to add timestamp to every row getting inserted. I want data getting inserted as following :
{
"Temperature": 50,
"Humidity": 30,
"Vibration": 100,
"Time": "2020-1-26 00:00:01",
"_id": {
"$id": "5e330be3f7577f640d2a0922"
},
timestamp:<CURRUNT TIME>
},
{
"Temperature": 55,
"Humidity": 34,
"Vibration": 50,
"Time": "2020-1-26 00:00:02",
"_id": {
"$id": "5e330be3f7577f640d2a0923"
},
timestamp:<CURRUNT TIME>
}
is there any way to make mongoDB add current timestamp auto like MySQL?
First of all you should not store date/time values as string! It will just generate trouble at later times. Better use
"Time": ISODate("2020-01-26T00:00:02Z")
"Time": new Date("2020-01-26 00:00:02") may also work
Then in general you don't need to insert a timestamp. Every document gets an internal _id identifier which contains also the time when it was inserted. You can try like this:
db.collection.aggregate([
{
$project: {
timestamp: {
$toDate: "$_id"
},
key: 1,
secrete: 1,
data: 1,
_id: 0
}
}
])
Result:
{
"data": [
{
"Humidity": 30,
"Temperature": 50,
"Time": "2018-02-26 01:00:00",
"Vibration": 100
},
{
"Humidity": 34,
"Temperature": 55,
"Time": "2018-02-26 01:00:00",
"Vibration": 50
}
],
"key": "121239",
"secrete": "Your_Device_Secrete",
"timestamp": ISODate("2018-02-26T00:00:00Z")
}
You can also query for it, e.g.
db.collection.find({
$expr: {
$gte: [ {"$toDate": "$_id"}, ISODate("2020-01-03T11:00:00Z") ]
}
})
However, if you like to insert timestamp explicitly then simply do it like this.
{
"Temperature": 50,
"Humidity": 30,
"Vibration": 100,
"_id": {
"$id": "5e330be3f7577f640d2a0923"
},
"timestamp": new Date()
}
Or "timestamp": ISODate() should also work
Another note, this embedded document "_id": {"$id": "5e330be3f7577f640d2a0923"} looks really strange. I assume this is a bug. The string look like a ObjectId object used for _id. Somehow you scratched it.
Update
I really recommend to use proper data types. In PHP the insert could look like this:
$mongo->db->collection->insertOne([
"timestamp" => new MongoDB\BSON\UTCDateTime(NULL),
"key" => "121239",
"secrete" => "Your_Device_Secrete",
"data" => [
[
"Temperature" => 50,
"Humidity" => 30,
"Vibration" => 100,
"Time" => new MongoDB\BSON\UTCDateTime(new DateTime("2020-1-26 00:00:01"))
],
[
"Temperature" => 55,
"Humidity" => 34,
"Vibration" => 50,
"Time" => new MongoDB\BSON\UTCDateTime(new DateTime("2020-1-26 00:00:02"))
]
]
]);
I also had similar requirements as yours while reading sensor values from DHT11 sensor in my IoT class. I was able to insert all the temperature and humidity readings into MongoDB but later while plotting the graph I realized that I would need the timestamps as well. After researching for a while, I came up with this query. However, it will create a new collection in the database.
Here, the new collection name is dht11-sensor-readings.
Please also refer to https://docs.mongodb.com/manual/reference/operator/aggregation/out/ for more.
db.collection.aggregate([
{
$addFields:{timestamp:{$toDate:"$_id"}
}
},
{ $out:"dht11-sensor-readings"
}
])

Return selected keys in collection for json

I have this data in method of controller as you see I deleted some keys in method:
$foods = Food::get()->map(function($value){
return collect($value->toArray())->except('pivot', 'deleted_at', 'created_at', 'updated_at');
});
return HttpHelpers::sendJsonData($foods, 200);
and the api response returns this:
{
"success": true,
"data": [
{
"id": 1,
"title": "food1",
"default_price": 2353465456,
"main_meal": 1,
"labels": [
{
"id": 1,
"title": "type1",
"type": "food",
"created_at": "2018-08-23 03:55:33",
"updated_at": "2018-08-23 03:55:33",
"pivot": {
"labelable_id": 1,
"label_id": 1,
"labelable_type": "App\\Models\\Panel\\Food"
}
}
]
},
{
"id": 2,
"title": "food2",
"default_price": 1000,
"main_meal": 0,
"labels": [
{
"id": 1,
"title": "type2",
"type": "food",
"created_at": "2018-08-23 03:55:33",
"updated_at": "2018-08-23 03:55:33",
"pivot": {
"labelable_id": 2,
"label_id": 1,
"labelable_type": "App\\Models\\Panel\\Food"
}
}
]
}
]
}
now my problem is that I do not want to return some keys, like labalable_id and labelable_type in pivot and created_at in labels, please offer me the best way
You can use the makeHidden method for hiding data to JSON. Haven't tried this code but, i think it should work.
https://laravel.com/docs/5.6/eloquent-serialization#hiding-attributes-from-json
$foods = Food::get()->map(function($value){
foreach($value->labels as $label){
$label = $label->makeHidden(['created_at']);
$label->pivot = $label->pivot->makeHidden(['labelable_id', 'labelable_type']);
}
return collect($value->toArray())->except('pivot', 'deleted_at', 'created_at', 'updated_at');
});
If the data response is coming through the stored procedure then in that case you need to store the Pivot table data in a temporary table and select the required keys that you require and display it through API in json.

QueryBuilder limit is working for only first row in cakephp 3.2 [duplicate]

This question already has an answer here:
How to limit contained associations per record/group?
(1 answer)
Closed 6 years ago.
Hii i am new to cakephp 3.2 v.
Here i have used model association (hasMany).
Here in bind section (campaign_videos) ,i want to fetch only one record ,
so for this ,i have put below code to manage it.
my actual data in db.
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
{
"id": 3,
"campaign_id": 1,
}
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
{
"id": 2,
"campaign_id": 2,
}
]
},
$fetchCampaignFirst = $this->Campaigns->find()->contain(['CampaignVideos' => ['queryBuilder' => function ($q) {
return $q->limit(1);
}]]);
I am getting this limit working for first data only ,not for others (others even not showing the fetched data).
Below i have written the output
Here i want to get an output like
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
{
"id": 2,
"campaign_id": 2,
}
]
}]
Only want the first record of campaign_videos.
Here after using the queryBuilder query , i am getting out put like.
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
]
}]
I am not getting any data for second id ,while data is present for it.
Please suggest me.
Thank you in advance.
Maybe I'm wrong (so feel free to downvote my answer) but I think it's not feasible using a simple query
in fact cake, when loading associated data, does a single query on the associated table and after that matches the rows with the corresponding ones in the main table.
So you would need to do a mysql query that find the first record of every category. i.e. something like what is described in this article
I think that the only (or maybe the simpler) solution is to loop through your records:
$campaigns= $this->Campaigns->find();
foreach($campaigns as $campaign)
{
$campaign->campaign_videos = $this->Campaigns->CampaignVideos-find()
->where(['campaign_id' => $campaign->id]
->order(['id' => 'asc'])
->limit(1);
}

How to get only first row of association table in cakephp 3.2 [duplicate]

This question already has an answer here:
How to limit contained associations per record/group?
(1 answer)
Closed 6 years ago.
Hii i am new to cakephp 3.2 v.
Here i have used model association (hasMany).
Here in bind section (campaign_videos) ,i want to fetch only one record ,
so for this ,i have put below code to manage it.
my actual data in db.
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
{
"id": 3,
"campaign_id": 1,
}
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
{
"id": 2,
"campaign_id": 2,
}
]
},
$fetchCampaignFirst = $this->Campaigns->find()->contain(['CampaignVideos' => ['queryBuilder' => function ($q) {
return $q->limit(1);
}]]);
I am getting this limit working for first data only ,not for others (others even not showing the fetched data).
Below i have written the output
Here i want to get an output like
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
{
"id": 2,
"campaign_id": 2,
}
]
}]
Only want the first record of campaign_videos.
Here after using the queryBuilder query , i am getting out put like.
[
{
"id": 1,
"user_id": 95,
"campaign_videos": [
{
"id": 1,
"campaign_id": 1,
},
]
},
{
"id": 2,
"user_id": 95,
"campaign_videos": [
]
}]
I am not getting any data for second id ,while data is present for it.
Please suggest me.
Thank you in advance.
Maybe I'm wrong (so feel free to downvote my answer) but I think it's not feasible using a simple query
in fact cake, when loading associated data, does a single query on the associated table and after that matches the rows with the corresponding ones in the main table.
So you would need to do a mysql query that find the first record of every category. i.e. something like what is described in this article
I think that the only (or maybe the simpler) solution is to loop through your records:
$campaigns= $this->Campaigns->find();
foreach($campaigns as $campaign)
{
$campaign->campaign_videos = $this->Campaigns->CampaignVideos-find()
->where(['campaign_id' => $campaign->id]
->order(['id' => 'asc'])
->limit(1);
}

Categories