How to GROUP BY multiple levels in Laravel. I've tried this code.
I've also used toArray() then array_values(), but same result as using values()
EDIT: Sorry, I wrote value() instead of values()
When using values(), product_name not showing.
// Controller
$products = DB::table('product_registrations')
// ->select(['product_name', 'color'])
->join('colors', 'colors.id', '=', 'product_registrations.color_id')
->join('sizes', 'sizes.id', '=', 'product_registrations.size_id')
->join('products', 'products.id', '=', 'product_registrations.product_id')
->get()
->groupBy(['product_name', 'color']);
// ->values(); // I've used values(), it worked but first level groupBy name missing
return response()->json(['products' => $products]);
---
I want something like:
products: [
product1: [
color1: {},
color2: {}
]
]
Without values()
{
"products": {
"light blue dress": {
"Ягаан": [
{
"id": 1,
"product_id": 1,
"color_id": 1,
"size_id": 6,
"color": "Ягаан",
"product_name": "light blue dress",
}
],
},
}
}
With values()
{
"products": [
{
"Ягаан": [
{
"id": 1,
"product_id": 1,
"color_id": 1,
"size_id": 6,
"color": "Ягаан",
"product_name": "light blue dress",
}
],
}
]
}
Try this one. I also have problem on this last week but I manage to get through.
$products::latest()->get();
$products = products->groupBy(function($product) {
return $product->name;
});
$products = products->map(function($product) {
return $product->groupBy(function($prod) {
return $prod->color;
});
});
return $products;
You can also optimize this method by using array_only this method is only for laravel
Related
I have two tables posts and images and I want to get all the posts and related images with below code:
$posts = Post::leftJoin('images','posts.postId','images.postId')
->where('countryId', $id)
->groupBy('posts.postId')
->orderby('posts.postId', 'desc')
->select('posts.*','images.*', 'posts.postId as postId')
->get();
But the problem is that I get only one image of the post instead of all images because one post have multiple images.
Current Json response is:
[
{
"postId": 103,
"text": 'This is the post text',
"countryId": 75,
"imageId": 152,
"imageLink": "C9hGzwVKlOrL.jpg",
"imageDescription": ""
},
...
]
And I want to change it like this:
[
{
"postId": 103,
"text": 'This is the post text',
"countryId": 75,
"images" : [
{
"imageId": 152,
"imageLink": "C9hGzwVKlOrL.jpg",
"imageDescription": "This is the 1st image description"
},
{
"imageId": 153,
"imageLink": "JHKJdiuIuoi.jpg",
"imageDescription": "This is the 2nd image description"
},
...
]
},
...
]
You shouldn't try to get hierarchical/nested data using one query. Eloquent has "Relationships" functionality for that: https://laravel.com/docs/8.x/eloquent-relationships#one-to-many
In your case you need to add "images" relation to Post model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function images()
{
return $this->hasMany(Image::class, 'postId', 'postId');
}
}
Then:
$posts = Post::where('countryId', $id)
->orderBy('postId', 'desc')
->select('posts.*','images.*', 'posts.postId as postId')
->get();
foreach ($posts as $post) {
$post->images; // = collection of all images related to this post
}
I am trying to retrieve the data saved as json in mysql. My migration looks like below:
Schema::create('items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->nullable();
$table->json('add_ons')->nullable();
$table->timestamps();
});
I have tried saving the below JSON from postman and it saved perfectly.
{
"itemName": "chicken",
"addons": {
"required": false,
"min": 2,
"max": 3,
"data": [
{
"name": "sauces",
"type": [
{
"name": "white sauce",
"type": [
{
"name": "whiteOne",
"price": 10
},
{
"name": "whiteTwo",
"price": 20
}
]
},
{
"name": "red sauce",
"price": 10
}
]
}
]
}
}
Now, I trying to retrieve the price of 'whiteOne' under 'white sauce' and getting nothing other than null or laravel error response.
I have tried
Item::whereJsonContains('add_ons->data->name','sauces')->get()
Item::whereJsonContains('add_ons->data->name','sauces')->find(16)
After saving the 'add_ons' column has below data:
{
"required": false,
"min": 2,
"max": 3,
"data": [
{
"name": "sauces",
"type": [
{
"name": "white sauce",
"type": [
{
"name": "whiteOne",
"price": 10
},
{
"name": "whiteTwo",
"price": 20
}
]
},
{
"name": "red sauce",
"price": 10
}
]
}
]
}
Can anyone help me ?
I used this function to get the value of the index.
public function search($array, $key, $value) {
// RecursiveArrayIterator to traverse an
// unknown amount of sub arrays within
// the outer array.
$arrIt = new \RecursiveArrayIterator($array);
// RecursiveIteratorIterator used to iterate
// through recursive iterators
$it = new \RecursiveIteratorIterator($arrIt);
foreach ($it as $sub) {
// Current active sub iterator
$subArray = $it->getSubIterator();
if ($subArray[$key] === $value) {
//$result[] = iterator_to_array($subArray);
$result = iterator_to_array($subArray);
}
}
return $result;
}
Now when I pass the values in the function I get the appropriate values.
$item = Item::where('id','=',16)->first();
$res = $this->search($item->add_ons['data'], 'name', 'whiteTwo');
echo $res["name"]." - ".$res['price'] ."<br>";
I want to get the average rates for each product.
I have a rates table which has a foreign key to product table,
the rates table is similar to this
when I try to get products with this code:
$stocks = Stocks::with('images:url,color', 'tags:tag', 'sizes', 'rates')
->get()
->pluckDistant('tags', 'tag')
->pluckDistant('sizes', 'size');
it returns this
[
{
"id": 10,
"name": "name",
"image": "1564964985mI7jTuQEZxD49SGTce6Qntl7U8QDnc8uhVxedyYN.jpeg",
"images": [
{
"url": "1564964985mI7jTuQEZxD49SGTce6Qntl7U8QDnc8uhVxedyYN.jpeg",
"color": ""
},
{
"url": "1564964985EV20c1jGvCVCzpCv2Gy9r5TnWM0hMpCBsiRbe8pI.png",
"color": ""
},
{
"url": "1564964985iFcMox6rjsUaM8CHil5oQ9HkrsDqTrqLNY1cXCRX.png",
"color": ""
}
],
"tags": [
"عطور"
],
"sizes": [],
"rates": [
{
"id": 1,
"stocks_id": 10,
"rate": 2
},
{
"id": 2,
"stocks_id": 10,
"rate": 4
}
],
}
]
How can I get the average of rates as "rates":3 using the eloquent relations to get them all by sql without php proccessing?
You could leverage something like Appending. Say you have a Product model which has a OneToMany relationship with Rate model.
Your Product model would look something like this:
class Product extends Model
{
protected $with = ['rates'];
protected $appends = ['average_rate'];
public function getAverageRateAttribute()
{
return $this->attributes['average_rate'] = $this->rates->avg('rate');
}
public function rates() {
return $this->hasMany(Rate::class);
}
}
Now anytime you query your products from the database, you'll have the rate appended with the result.
array:7 [▼
"id" => 1
"created_at" => "2019-08-12 14:08:09"
"updated_at" => "2019-08-12 14:08:09"
"average_rate" => 4.5
"rates" => array:2 [▶]
]
However, be aware of causing n+1 problem. If you're using this approach make sure to always eager load your rates.
You could just use join and use aggregate function on rates table.
Stocks::with('images:url,color', 'tags:tag', 'sizes')
->join('rates', 'rates.stocks_id', '=', 'stocks.id')
->selectRaw('stocks.*')
->selectRaw('AVG(rates.rate) as average_rating')
->selectRaw('tags.*')
->selectRaw('sizes.*')
->selectRaw('images.*')
->groupBy('stocks.id')
->get()
im working on Laravel Rest Api with passeport ,
in return response()->json() i want to trim the brackets
I've tried trim($json,'[]') function but it's not what i want
public function getOffers()
{
$offers = Offer::where('type', 'primary')->where('active', 1)->get();
$paks = Offer::where('type', 'pack')->where('active', 1)->get();
return response()->json([
'offersList' => $offers,
'packsList' => $paks,
], 200);
}
i expect the output will be
{
"offersList": {
{
"id": 3,
"name": "Gold",
"description": null
}
},
"packsList":[]
}
but the actual result is
{
"offersList": [
{
"id": 3,
"name": "Gold",
"description": null
}
],
"packsList":[]
}
$offers is a collection, and thus an array in JSON.
If $offers should be a single item, use first() instead of get() and it will be rendered as a single object in your JSON instead of an array of objects.
$offers = Offer::where('type', 'primary')->where('active', 1)->first();
If $offers should, at times, contain multiple offers, leave it as-is; it's correct!
Braces {} nested in another object is not valid JSON.
Objects can be used in property values and as array elements.
Not valid JSON
{
"offersList": {
{
"id": 3,
"name": "Gold",
"description": null
}
}
}
Valid option 1
{
"offersList": [
{
"id": 3,
"name": "Gold",
"description": null
}
]
}
Valid option 2
{
"offersList": {
"id": 3,
"name": "Gold",
"description": null
}
}
You can use online linters to quickly validate your JSON structure.
https://jsonformatter.curiousconcept.com/
I am new to MongoDB and I am trying to turn SQL queries into MongoDB queries. But can't seem to find any way to turn a SQL query with a subquery to mongoDB.
for example:
SELECT article, dealer, price
FROM shop
WHERE price=(SELECT MAX(price) FROM shop);
I tried the following, but it doesn't seem to work.
db.shop.group({
"initial": {},
"reduce": function(obj, prev) {
prev.maximumvalueprice = isNaN(prev.maximumvalueprice) ? obj.price :
Math.max(prev.maximumvalueprice, obj.price);
}}).forEach(
function(data){
db.shop.find({
"price": data
},
{
"article": 1,
"dealer": 1,
"price": 1
})
})
How do I convert this SQL query into a MongoDB query?
If you are using MongoDB v. 3.2 or newer you can try to use $lookup.
Try to use aggregation:
$sort your collection by price by DESC;
set $limit to 1 (it will take a first document, which will be with biggest price);
then use $lookup to select the documents from the same collection by max price and set it to tmpCollection element;
$unwind tmpCollection;
$replaceRoot - change document root to $tmpCollection
Example:
db.getCollection("shop").aggregate([
{$sort: {"price":-1}},
{$limit: 1},
{$lookup: {
from: "shop",
localField: "price",
foreignField: "price",
as: "tmpCollection"
}},
{$unwind: "$tmpCollection"},
{$replaceRoot: {newRoot:"$tmpCollection"}}
]);
Looks like you need the aggregation framework for this task using $first within a $group pipeline stage on ordered documents. The initial pipeline step for ordering the documents in the collection is $sort:
db.shop.aggregate([
{ "$sort": { "price": -1 } }, // <-- sort the documents first in descending order
{
"$group": {
"_id": null,
"article": { "$first": "$article" },
"dealer": { "$first": "$dealer" },
"price": { "$first": "$price" }
}
}
])
or using $last
db.shop.aggregate([
{ "$sort": { "price": 1 } }, // <-- note the sort direction
{
"$group": {
"_id": null,
"article": { "$last": "$article" },
"dealer": { "$last": "$dealer" },
"price": { "$last": "$price" }
}
}
])