Laravel return data based on relation result - php

PostController.php
$customers = $query->orderBy('id', 'desc')->with('agents:agents.id')->get();
foreach ($customers as $customer) {
$customer->calculator = $this->calculator($customer);
}
return response()->json($customers, 200 );
Post.php
function agents()
{
return $this->belongsToMany('App\Agent','files','post_id','agent_id');
}
This return right data, like this:
[{
"id": 5,
"hash": "SqB29tkfm1dwGsXp4ZCV",
"agents": [{
"id": 1,
"pivot": {
"post_id": 5,
"agent_id": 1
}
}]
},
{
"id": 4,
"hash": "SqH29tkfm1dwGsXp4ZCV",
"agents": []
},
{
"id": 3,
"hash": "RqH29tkfm1dwGsXp4ZCV",
"agents": [{
"id": 1,
"pivot": {
"post_id": 3,
"agent_id": 1
}
}]
},
{
"id": 1,
"hash": "RqH29tkfm1dwGrXp4ZCV",
"agents": [{
"id": 1,
"pivot": {
"post_id": 1,
"agent_id": 1
}
}]
}
]
But what I want is return just those data that has empty agents [] , in this case, should return just id 4 because agents array is empty. how can I do this?

Try this :
$customers = $query->orderBy('id', 'desc')->whereDoesntHave('agents')->get();
If you want to get the customer who doesn't have agents.
Read more at here

you can use both doesntHave or whereDoesntHave like
$customers = $query->orderBy('id', 'desc')->doesntHave('agents')->get();
or
$customers = $query->orderBy('id', 'desc')->whereDoesntHave('agents')->get();

Related

How to get data according to group in laravel

Hello all I am using laravel and I am having some problem below is my array
[
{
"id": "375c572b-5c54-4c91-bb11-dda23bcf8052",
"user_id": "a8dd7771-fc0e-46d3-b5a6-5a9ebaa89b9f",
"group_id": "37b82ef4-c211-49a8-8e1c-a62c0f107219"
},
{
"id": "809ee65e-e5b7-4519-ba7b-9d98ef0a4e3a",
"user_id": "30517691-89b1-4247-9b74-522350e82622",
"group_id": "37b82ef4-c211-49a8-8e1c-a62c0f107219"
},
{
"id": "8d764272-3a5c-402f-8488-a641e3567e3e",
"user_id": "a8dd7771-fc0e-46d3-b5a6-5a9ebaa89b9f",
"group_id": "a24a9b00-a805-4142-99f4-3384bbb842f0"
}
]
from the above array I want the result like below I want data with same group_id
[
{
"id": "375c572b-5c54-4c91-bb11-dda23bcf8052",
"user_id": "a8dd7771-fc0e-46d3-b5a6-5a9ebaa89b9f",
"group_id": "37b82ef4-c211-49a8-8e1c-a62c0f107219"
},
{
"id": "809ee65e-e5b7-4519-ba7b-9d98ef0a4e3a",
"user_id": "30517691-89b1-4247-9b74-522350e82622",
"group_id": "37b82ef4-c211-49a8-8e1c-a62c0f107219"
},
]
below is my code I tried but I am not getting result
$get_group_ids = DB::table('auc_chat_group_users')
->select("id","user_id","group_id")
->whereIn('user_id', $request->user_id)
->orWhere('user_id',auth()->user()->id)
->distinct('group_id')
->groupBy("id","user_id","group_id")
->orderBy('group_id')
->get();
pluck() should solve your problem

Laravel pass parameter to its distant relationship (translate children)

I have categories with id, parent_id, slug , pivot table category_language which columns are id,category_id,language_id,value
As you can see I can translate parent category, but can't send desired $lang_id to children translations, so each children having all translations
here is what I get:
{
"id": 1,
"parent_id": 0,
"slug": "personal-computers",
"created_at": "2019-12-27 15:05:31",
"updated_at": "2019-12-27 15:05:31",
"children": [
{
"id": 3,
"parent_id": 1,
"slug": "accessories-for-pc",
"created_at": "2019-12-27 15:05:32",
"updated_at": "2019-12-27 15:05:32",
"translations": [
{
"id": 1,
"code": "en",
"name": "English",
"pivot": {
"category_id": 3,
"language_id": 1,
"value": "Acc for PC",
"id": 7
}
},
{
"id": 2,
"code": "ru",
"name": "Русский",
"pivot": {
"category_id": 3,
"language_id": 2,
"value": "Аксессуары для ноутбуков и ПК",
"id": 8
}
},
{
"id": 3,
"code": "ro",
"name": "Romana",
"pivot": {
"category_id": 3,
"language_id": 3,
"value": "aksessuari-dlya-noutbukov-i-pk-ro",
"id": 9
}
}
]
}
],
"translations": [
{
"id": 1,
"code": "en",
"name": "English",
"pivot": {
"category_id": 1,
"language_id": 1,
"value": "PC",
"id": 1
}
}
]
}
Controller:
return Category::with('children')
->with(array('translations'=>function($query) use ($lang_id){
$query->where('language_id',$lang_id);
}))
->where('parent_id',0)->first();
Model
class Category extends Model
{ ..
public function translations()
{
return $this->belongsToMany('App\Models\Translation','category_language', 'category_id' ,'language_id' )->withPivot('value','id');
}
public function children()
{
return $this->hasMany( 'App\Models\Category' , 'parent_id' , 'id' )->with('translations');
}
}
you can add condition in children method
public function children()
{
return $this->hasMany( 'App\Models\Category' , 'parent_id' , 'id' )->with('translations')->where('language_id', 1);
}
Dry7 answer was close to the one I've implemented later, so I upvoted him.
Finally in model I've added: ...->where('language_id',helper_SetCorrectLangIdForQuery());
and function helper_SetCorrectLangIdForQuery is using global helper of Laravel request()->lang . If lang=enz, than it takes default language from another helper.

How to calculate the total amount for similar keys in PHP using Laravel eloquent/collections

I currently have the below json response that the API is returning. I am able to return it using Laravel Eloquent. There are several users and each user has a several receipts. A receipt has types and status. I want to try to get the total sum amount for each receipt that is related to its type and status. I was able to return the below json response using
$this->user->with('receipts')->has('receipts')->get(['id', 'name']);
I have tried using multiple laravel collections methods https://laravel.com/docs/5.8/collections#available-methods
But I am still unable to get the desired response.
{
"id": 1,
"name": "kent",
"receipts": [
{
"id": 1,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 100
},
{
"id": 2,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 100
},
{
"id": 3,
"user_id": 1,
"type_id": 2,
"status": 1,
"amount": 50
},
{
"id": 4,
"user_id": 1,
"type_id": 2,
"status": 0,
"amount": 30
},
{
"id": 5,
"user_id": 1,
"type_id": 2,
"status": 0,
"amount": 30
},
{
"id": 6,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 20
},
{
"id": 7,
"user_id": 1,
"type_id": 1,
"status": 1,
"amount": 10
}
]
},
{
"id": 2,
"name": "allison",
"receipts": [
{
"id": 9,
"user_id": 2,
"type_id": 1,
"status": 0,
"amount": 20
}
]
}
]
I expect to get the below
{
"id": 1,
"name": "kent",
"receipts": [
{
"performance and deleted": 220,
"performance and not deleted": 10,
"project and deleted": 60,
"project and deleted": 50
}
]
},
{
"id": 2,
"name": "allison",
"receipts": [
{
"performance and deleted": 20,
"performance and not deleted": 0,
"project and deleted": 0,
"project and not deleted": 0
}
]
}
]
You should be able to get the sum of amount with
$this->user->with(['receipts' => function($query) {
$query->selectRaw("SUM(amount) as amount, type_id, status, user_id")->groupBy('type_id', 'status', 'user_id');
}])->has('receipts')->get(['id', 'name']);
You can use collection methods to get the desired output
$this->user->with(['receipts' => function($query) {
$query->selectRaw("SUM(amount) as amount, type_id, status, user_id")->groupBy('type_id', 'status', 'user_id');
}])->has('receipts')->get(['id', 'name'])
->each(function ($user) {
$user->setRelation(
'receipts',
$user->receipts->mapWithKeys(function ($receipt) {
return [
$receipt->type_id . ' and ' . $receipt->status => $receipt->amount // format the key as you wish
];
})
);
})
You may use foreach and other loops to make the json you want!
use This function to convert your collection to the json you want :
public function convert(Collection $collection)
{
$result_collection = $collection;
$payment_collections = [];
foreach ($result_collection->receipts as $receipt)
{
$payment["type_id${receipt->type_id} and status${$receipt->status}"] = $receipt->amount;
}
$result_collection->receipts = $payment_collections;
return $result_collection;
}
And This is same way to get total amount. Just put an foreach and add each amount to a variable that initialized with 0;
and there is other ways like change toArray function in your Resource Collection.
I wrote the script assuming your data is a PHP array so you may change some part of my code.
For example you may change:
$row['receipts']
// To
$row->receipts
anyway
// The function in your controller
function index(){
$users=User::whereHas('receipts')->with('receipts')->get()->toArray();
return convert($users);
}
// The helper function
function convert($data){
$data=collect($data);
$allTypes=[];
$allStatuses=[];
return $data->each(function($row) use (&$allTypes,&$allStatuses){
$types=collect($row['receipts'])->pluck('type_id')->toArray();
$statuses=collect($row['receipts'])->pluck('status')->toArray();
$allTypes=array_unique(array_merge($allTypes,$types));
$allStatuses=array_unique(array_merge($allStatuses,$statuses));
})->map(function ($row,$index) use (&$allTypes,&$allStatuses){
$result=[];
$receipts=collect($row['receipts']);
foreach ($allTypes as $type){
foreach ($allStatuses as $status){
$result["type_id {$type} and status {$status}: "]=$receipts->where('type_id',$type)->where('status',$status)->sum('amount');
}
}
$row['receipts']=$result;
return $row;
});
}

Laravel 5.3 - Merge array based on 2 matching keys?

Given the following two arrays, how can they be merged efficiently to result in the third array?
productData
$productData =
[
{
"product_id": 4,
"type": "electronic",
"name": "monitor",
"specs": {
"HDMI": true,
"VGA": false
}
},
{
"product_id": 5,
"type": "electronic",
"name": "HDMI cable",
"specs": {
"length": "3ft"
}
},
{
"product_id": 6,
"type": "kitchen",
"name": "spoon"
}
]
products
$products =
{
"products": 3,
"per_page": 10,
"current_page": 1,
"data": [
{
"id": 4,
"product_type": "electronic",
"product_id": 6
},
{
"id": 6,
"type": "electronic",
"product_id": 5
},
{
"id": 9,
"type": "kitchen",
"product_id": 4
}
]
}
productsFinal ($productData merged into $products - based on matching combo of product_id/product_id and type/product_type)
$productsFinal =
{
"products": 3,
"per_page": 10,
"current_page": 1,
"data": [
{
"id": 4,
"product_type": "electronic",
"product_id": 6,
// How to merge product data and wrap with "data" key
"data": {
"product_id": 6,
"type": "kitchen",
"name": "spoon"
}
},
{
"id": 6,
"type": "electronic",
"product_id": 5,
// How to merge product data and wrap in "data" key
"data": {
"product_id": 5,
"type": "electronic",
"name": "HDMI cable",
"specs": {
"length": "3ft"
}
}
},
{
"id": 9,
"type": "kitchen",
"product_id": 4,
// How to merge product data and wrap in "data" key
"data": {
"product_id": 6,
"type": "kitchen",
"name": "spoon"
}
}
]
}
I tried different things for the outcome in a foreach loop but still cannot get it to render as intended:
foreach($productData as $productDataItem) {
// when $productDataItem.product_id == $product.product_id && $productDataItem.type == $product.product_type
// move the matching $productDataItem object into matching $product object, wrapped in a new "data" key
}
I don't know Laravel too well. However you can join your data objects quite easily:
<?php
$productData = json_decode('[
{
"product_id": 4,
"type": "electronic",
"name": "monitor",
"specs": {
"HDMI": true,
"VGA": false
}
},
{
"product_id": 5,
"type": "electronic",
"name": "HDMI cable",
"specs": {
"length": "3ft"
}
},
{
"product_id": 6,
"type": "kitchen",
"name": "spoon"
}
]');
$products = json_decode('{
"products": 3,
"per_page": 10,
"current_page": 1,
"data": [
{
"id": 4,
"type": "electronic",
"product_id": 6
},
{
"id": 6,
"type": "electronic",
"product_id": 5
},
{
"id": 9,
"type": "kitchen",
"product_id": 4
}
]
}');
// combine both data objects
foreach($products->data As &$p) {
foreach($productData As $d) {
if(property_exists($p, "product_id") && property_exists($d, "product_id") && property_exists($p, "type") && property_exists($d, "type")) {
if($p->product_id==$d->product_id && $p->type==$d->type) {
//$p = (object) array_merge((array) $p, (array) $d);
$p->data = $d; // updated answer
continue;
}
}
}
}
echo("<pre>");
echo json_encode($products, JSON_PRETTY_PRINT);
?>
You can test the code here: http://sandbox.onlinephpfunctions.com/code/98a50c35ee32c30f0d2be1661f7afb5895174cbe
Update: http://sandbox.onlinephpfunctions.com/code/aeebfdcf4f4db5e960260e931982570cfed19e0e
I would suggest to check this package dingo/api. I assume you want to display some kind of JSON response. Take a look at Transformers. You can do something like this :
<?php
namespace App\Http\Transformers;
use App\Http\Controllers\ProductData;
use League\Fractal\TransformerAbstract;
class ProductsDataTransformer extends TransformerAbstract
{
/**
* Turn this item object into a generic array
*
* #return array
*/
public function transform(ProductData $productdata)
{
return [
'id' => $productdata->id,
'product_type' => $productdata->product_type,
'product /*or data*/' => Product::find($productdata->product_id),
];
}
}
This would find the product by it's ID and look like this :
{
"id": 4,
"product_type": "electronic",
"product" {
"product_id": 6,
"type": "kitchen",
"name": "spoon"
},
},
You can then also create a transformer for Product to take care of your specs attribute to do the same thing.

Getting unique results with elasticsearch acorrding to field

I'm using FOSElasticaBundle with Symfony2 on my project and there are entry and user tables on MySQL database and each entry belongs to one user.
I want to get just one entry per a user among the whole entries from the database.
Entries Representation
[
{
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"
}
},
{
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"
}
},
{
"id": 3,
"name": "Dolar sit amet",
"user": {
"id": 17,
"username": "foo"
}
},
]
Expected result is:
[
{
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"
}
},
{
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"
}
}
]
But it returns all entries on table. I've tried to add an aggregation to my elasticsearch query and nothing changed.
$distinctAgg = new \Elastica\Aggregation\Terms("distinctAgg");
$distinctAgg->setField("user.id");
$distinctAgg->setSize(1);
$query->addAggregation($distinctAgg);
Is there any way to do this via term filter or anything else? Any help would be great. Thank you.
Aggregations are not easy to understand when you are used to MySQL group by.
The first thing, is that aggregations results are not returned in hits, but in aggregations. So when you get the result of your search, you have to get aggregations like that :
$results = $search->search();
$aggregationsResults = $results->getAggregations();
The second thing is that aggregations wont return you the source. With the aggregation of your example, you will only know that you have 1 user with ID 15, and 2 users with ID 15.
E.g. with this query :
{
"query": {
"match_all": {}
},
"aggs": {
"byUser": {
"terms": {
"field": "user.id"
}
}
}
}
Result:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [ ... ]
},
"aggregations": {
"byUser": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 17,
"doc_count": 2
},
{
"key": 15,
"doc_count": 1
}
]
}
}
}
If you want to get results, the same way you would do with a GROUP BY in MySQL, you have to use a top_hits sub-aggregation:
{
"query": {
"match_all": {}
},
"aggs": {
"byUser": {
"terms": {
"field": "user.id"
},
"aggs": {
"results": {
"top_hits": {
"size": 1
}
}
}
}
}
}
Result:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [ ... ]
},
"aggregations": {
"byUser": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 17,
"doc_count": 2,
"results": {
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "test_stackoverflow",
"_type": "test1",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"
}
}
}
]
}
}
},
{
"key": 15,
"doc_count": 1,
"results": {
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test_stackoverflow",
"_type": "test1",
"_id": "2",
"_score": 1,
"_source": {
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"
}
}
}
]
}
}
}
]
}
}
}
More informations on this page : https://www.elastic.co/blog/top-hits-aggregation

Categories