I have 4 table products, properties, property_items, property_product with relations like this
Product has many properties.
Property has many property_items.
Product has many property_items.
Property_product is intermediary table.
-- products --
Id name
1 Arrabiata
2 Bolognese
--properties --
Id name
1 Pasta type
2 Size
-- property_items --
Id name value property_id
1 Spinach spaghetti ..... 1
2 Linguine ..... 1
3 Spaghetti ..... 1
4 Small .... 2
5 Medium .... 2
6 Large ... 2
-- property_product --
product_id property_id property_item_id
1 1 1
1 1 2
1 2 4
1 2 6
2 1 2
2 1 3
2 2 5
I try use Gii to create those models with relations .
class Products extends \yii\db\ActiveRecord
{
//code
....
public function getProperties()
{
return $this->hasMany(Properties::className(), ['id' => 'property_id'])
->viaTable('property_product', ['product_id' => 'id']);
}
}
class Properties extends \yii\db\ActiveRecord
{
//code
...
public function getPropertyItems()
{
return $this->hasMany(PropertyItems::className(), ['property_id' => 'id']);
}
}
I want to query data with multi nested relation.
How can i create json response with below format in one active record query ?
[
{
"id": "1",
"name": "Arrabiata",
"properties": [
{
"id": "1",
"name": "Pasta type",
"property_items" : [
{
"id": "1",
"name": "Spinach spaghetti",
},
{
"id": "2",
"name": "Linguine",
},
]
},
{
"id": "2",
"name": "Size",
"property_items" : [
{
"id": "4",
"name": "Small",
},
{
"id": "6",
"name": "Large",
},
]
},
],
},
{
"id": "2",
"name": "Bolognese",
"properties": [
{
"id": "1",
"name": "Pasta type",
"property_items" : [
{
"id": "2",
"name": "Linguine",
},
{
"id": "3",
"name": "Spaghetti",
},
]
},
{
"id": "2",
"name": "Size",
"property_items" : [
{
"id": "5",
"name": "Medium",
},
]
},
]
}]
I use this query but it took too much perfomance
Menus::find()->with(['products' => function ($query) {
$query->with(['properties']);
}])
->where(['>', 'status', 0])
->andWhere(['resid' => $id])->asArray()->all();;
foreach ($menus as &$menu) {
foreach ($menu['products'] as &$product) {
foreach ($product['properties'] as &$property) {
$propertyItems = PropertyItems::find()->where(['property_id' => $property['id']]
)
->leftJoin('property_product', 'property_items.id = property_product.property_item_id')
->where(['property_product.product_id' => $product['id'],
'property_product.property_id' => $property['id']])
->asArray()->all();
$property['propertyItems'] = $propertyItems;
}
}
}
If I use this query
Menus::find()->with(['products' => function ($query) {
$query->with(['properties' => function ($query) {
$query->with(['propertyItems']);
}
]);
}
])->asArray()->all();
But the result not same as i expected because all property_items will show up in properties instead of depend on relating with products via table "property_product"
[
{
"id": "1",
"name": "Arrabiata",
"properties": [
{
"id": "1",
"name": "Pasta type",
"property_items" : [
{
"id": "1",
"name": "Spinach spaghetti",
},
{
"id": "2",
"name": "Linguine",
},
{
"id": "3",
"name": "Spaghetti",
},
]
},
{
"id": "2",
"name": "Size",
"property_items" : [
{
"id": "4",
"name": "Small",
},
{
"id": "6",
"name": "Large",
},
{
"id": "5",
"name": "Medium",
},
]
},
],
},
{
"id": "2",
"name": "Bolognese",
"properties": [
{
"id": "1",
"name": "Pasta type",
"property_items" : [
{
"id": "1",
"name": "Spinach spaghetti",
},
{
"id": "2",
"name": "Linguine",
},
{
"id": "3",
"name": "Spaghetti",
},
]
},
{
"id": "2",
"name": "Size",
"property_items" : [
{
"id": "4",
"name": "Small",
},
{
"id": "6",
"name": "Large",
},
{
"id": "5",
"name": "Medium",
},
]
}
]
}]
Thanks in advance.
You have to override the function fields() of the Products and Properties models.
for example:
class Products extends ActiveRecord {
function fields(){
return ['properties'];
}
}
class Properties extends ActiveRecord {
function fields(){
return ['property_items'];
}
}
Related
I am building a Laravel app that connected with MongoDB. Now I am facing an issue when query data from the database.
table name: Employee
[
{
"_id": 1,
"name": "user 1",
"managers": [
{
"id": 321,
"user_id": 1,
"ack_groups: [
["2","3", "4"],
["2", "5", "6"]
]
},
......
]
},
{
"_id": 2,
"name": "user 2",
"managers": [
{
"id": 3213,
"user_id": 2,
"ack_groups: [
["6","7", "8"],
["2", "5", "6"]
]
},
......
]
},
{
"_id": 3,
"name": "user 3",
"managers": [
{
"id": 321,
"user_id": 3,
"ack_groups: [
["8","9", "14"],
["12", "15", "16"]
]
},
......
]
},
]
I am trying to query list of employees data from Employee table with some conditions. The condition is that I want to get list of employees where ac_groups in managers equal to 2.
Then the output should be:
[
{
"_id": 1,
"name": "user 1",
"managers": [
{
"id": 321,
"user_id": 1,
"ack_groups: [
["2","3", "4"],
["2", "5", "6"]
]
},
......
]
},
{
"_id": 2,
"name": "user 2",
"managers": [
{
"id": 3213,
"user_id": 2,
"ack_groups: [
["6","7", "8"],
["2", "5", "6"]
]
},
......
]
},
]
What I have tried in code: Employee::where('verify_routes.managers.ack_groups', '=', "2")->get();
Forum: "Find in array value"
Doc: Specific Operators
This should work:
Employee::where('verify_routes.managers.ack_groups', 'all', [2])->get();
I am starting to work with laravel and to obtain my data I use eloquent, so I have a collection of data that looks more or less like this:
[
{
"title": "Expense",
"name": "list",
"id": 2
},
{
"title": "Expense",
"name": "register",
"id": 3
},
{
"title": "Expense",
"name": "show",
"id": 4
},
{
"title": "Expense",
"name": "update",
"id": 5
},
{
"title": "Expense",
"name": "remove",
"id": 6
},
{
"title": "Income",
"name": "list",
"id": 7
},
{
"title": "Income",
"name": "register",
"id": 8
},
{
"title": "Income",
"name": "show",
"id": 9
},
{
"title": "Income",
"name": "update",
"id": 10
},
{
"title": "Income",
"name": "remove",
"id": 11
}
]
So I was wondering how I could transform this collection with the methods provided by it, or do I need to work with native arrays so that the collection I showed earlier can be as follows:
[
{
"title":"Expense",
"permissions":[
{
"id":2,
"name":"list"
},
{
"id":3,
"name":"show"
},
{
"id":4,
"name":"register"
},
{
"id":5,
"name":"update"
},
{
"id":6,
"name":"remove"
}
]
},
{
"title":"Income",
"permissions":[
{
"id":7,
"name":"list"
},
{
"id":8,
"name":"show"
},
{
"id":9,
"name":"register"
},
{
"id":10,
"name":"update"
},
{
"id":11,
"name":"remove"
}
]
}
]
This is more a PHP issue rather than a Laravel one. Eloquent won't change it for you, unless the permissions are linked to another table and then you will get them in that format, what you need to do is simply edit your array natively.
you can use groupBy in laravel collection
like this
$collection = new Collection([
{
"title": "Expense",
"name": "list",
"id": 2
},
{
"title": "Expense",
"name": "register",
"id": 3
},
{
"title": "Expense",
"name": "show",
"id": 4
},
{
"title": "Expense",
"name": "update",
"id": 5
},
{
"title": "Expense",
"name": "remove",
"id": 6
},
{
"title": "Income",
"name": "list",
"id": 7
},
{
"title": "Income",
"name": "register",
"id": 8
},
{
"title": "Income",
"name": "show",
"id": 9
},
{
"title": "Income",
"name": "update",
"id": 10
},
{
"title": "Income",
"name": "remove",
"id": 11
}
]);
$grouped = $collection->groupBy('title');
$grouped->toArray();
i'm new in laravel and php and now i wanna create a rest api
I have this query:
$questions = Question::with(
array('picture' => function($query){
$query>select('question_id','picture_name')>pluck('picture_name')>all();
},
'user'=>function($query){
$query->select('id','image','name');
}))->get()->toArray();
my query return this json:
{
"questions:": [
{
"id": 1,
"title": "23",
"caption": "last",
"address": "lsdbabfd",
"picture": [
{
"question_id": 1,
"picture_name": "1527484678.jpg"
},
{
"question_id": 1,
"picture_name": "1527485120.jpg"
}
],
"user": {
"id": 1,
"image": "defaultPicture",
"name": "alex"
}
}
]
}
but i want this json:
{
"questions:": [
{
"id": 1,
"title": "23",
"caption": "last",
"address": "lsdbabfd",
"picture": [
"1527484678.jpg",
"1527485120.jpg"
],
"user": {
"id": 1,
"image": "defaultPicture",
"name": "alex"
}
}
]
}
how can i do that?
i already tried to do that with Laravel pluck method and Eloquent Mutators
you can add attribute method
class Question extends Model
{
...
protected $appends = ['pictures'];
public function getPicturesAttribute()
{
return $this->pictures->pluck('picture_id');
}
}
I have a list of (the result of a query in DB) like this:
[
{
"id": "1",
"parent_id": null,
"title": "مدادنوکی",
"url": "/medadnoki"
},
{
"id": "2",
"parent_id": null,
"title": "جامعه",
"url": "/commiunity"
},
{
"id": "5",
"parent_id": "1",
"title": "درباره ی مدادنوکی",
"url": "/about"
},
{
"id": "6",
"parent_id": "1",
"title": "درباره ی مدادنوکی",
"url": "/about"
},
{
"id": "7",
"parent_id": "2",
"title": "همکاران",
"url": "/co-worker"
},
{
"id": "8",
"parent_id": "2",
"title": "اساتید",
"url": "/masters"
}
]
But I want to create an object like this:
[
{
"title": "مدادنوکی",
"url": "/medadnoki",
"subs" : [
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
}
]
},
{
"title": "جامعه",
"url": "/soc",
"subs" : [
{
"title": "همکاران",
"url": "/co-work"
},
{
"title": "اساتید",
"url": "/masters"
}
]
}
]
I have handled this process with two foreach in php and it means I process data twice and it is not efficient and will be slow.
Is there any Idea to doing this with just one foreach?
using one foreach means faster than two foreach twice and It will show the result in big data
Assuming you have the results in an order where the parents appear in the results before any children they may have, this should work:
$nested = [];
foreach($results as $r) {
if($r['parent_id'] === null) {
$nested[$r['id']] = [
'title' => $r['title'],
'url' => $r['url'],
'subs' => []
];
continue;
}
$nested[$r['parent_id']]['subs'][] = [
'title' => $r['title'],
'url' => $r['url']
];
}
$nested = array_values($nested);
I have a json tree with categories,
I would like to obtain the last level of elements for each different category.
For example on this json:
[
{
"category_id": "3",
"parent_id": "2",
"name": "Women",
"categories": [
{
"category_id": "11",
"parent_id": "3",
"name": "Clothing",
"categories": [
{
"category_id": "30",
"parent_id": "11",
"name": "T-shirts",
"categories": null
},
{
"category_id": "33",
"parent_id": "11",
"name": "jeans",
"categories": null
}
]
}
]
},
{
"category_id": "5",
"parent_id": "2",
"name": "Footwear ",
"categories": [
{
"category_id": "15",
"parent_id": "5",
"name": "Rings",
"categories": [
{
"category_id": "51",
"parent_id": "15",
"name": "Small Leathers",
"categories": null
}
]
},
{
"category_id": "16",
"parent_id": "5",
"name": "Bands",
"categories": [
{
"category_id": "41",
"parent_id": "16",
"name": "boots",
"categories": null
}
]
},
{
"category_id": "48",
"parent_id": "5",
"name": "Bracelets",
"categories": [
{
"category_id": "55",
"parent_id": "48",
"name": "Cocktail",
"categories": null
}
]
}
]
}
]
The result would be an array (T-shirts, Jeans, Small Leathers, boots, cocktail)
What I was thinking is to decode it on an array and search filter the array with all the categories that are null, but I'm not sure if it's the best option because the object have different levels.
(I'm sorry for the English)
Json string is not a valid. It can be made valid by enclosing the json string in {}.
$json = '{"categories": [
{
"category_id": "3",
"parent_id": "2",
"name": "Women",
"categories": [
{
"category_id": "11",
"parent_id": "3",
"name": "Clothing",
"categories": [
{
"category_id": "30",
"parent_id": "11",
"name": "T-shirts",
"categories": null
},
{
"category_id": "33",
"parent_id": "11",
"name": "jeans",
"categories": null
}
]
}
]
},
{
"category_id": "5",
"parent_id": "2",
"name": "Footwear ",
"categories": [
{
"category_id": "15",
"parent_id": "5",
"name": "Rings",
"categories": [
{
"category_id": "51",
"parent_id": "15",
"name": "Small Leathers",
"categories": null
}
]
},
{
"category_id": "16",
"parent_id": "5",
"name": "Bands",
"categories": [
{
"category_id": "41",
"parent_id": "16",
"name": "boots",
"categories": null
}
]
},
{
"category_id": "48",
"parent_id": "5",
"name": "Bracelets",
"categories": [
{
"category_id": "55",
"parent_id": "48",
"name": "Cocktail",
"categories": null
}
]
}
]
}
]}';
Decode the json string in to php opject
$json_object = json_decode($json);
Use this recursive function to fetch get all the last level categories in a array.
function getLastCategories($object){
$last_categories = array();
if(is_array($object->categories)){
foreach($object->categories as $categories){
$last_categories = array_merge( $last_categories, getLastCategories($categories));
}
}else{
$last_categories[]=$object->name;
}
return $last_categories;
}
print_r(getLastCategories($json_object));
Output:
Array
(
[0] => T-shirts
[1] => jeans
[2] => Small Leathers
[3] => boots
[4] => Cocktail
)
You can do this using recursive iterators.
$categories = json_decode($json);
// create the iterator
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($categories));
// iterate recursively
foreach ($iterator as $key => $subcategories) {
// if the 'categories' key is empty for the current level...
if ($key == 'categories' && !$subcategories) {
// then add the value of the 'name' key for the current level to your result array.
$result[] = $iterator->getSubIterator()->offsetGet('name');
}
}
This may not be the most efficient way to do it, but it makes the code pretty simple.