Laravel mongodb search data in object - php

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();

Related

how to eager loading nested relations and not repeat them at top level?

a have a comments table that has these fields: id, body, parent_id
each comment can have comments, that's why it has a parent_id column.
class Comment extends Model
{
public function comments()
{
return $this->HasMany($this, 'parent_id');
}
}
It can have child comments up to two levels only.
In my controller I retrieve the information this way:
return Comment::with('comments.comments')->get();
The resulting response is like this:
[
{
"id": 1,
"body": "test",
"parent_id": null,
"comments": [
{
"id": 2,
"body": "test",
"parent_id": 1,
"comments": [
{
"id": 3,
"body": "test",
"parent_id": 2
},
{
"id": 4,
"body": "test",
"parent_id": 2
}
]
},
{
"id": 5,
"body": "test",
"parent_id": 1,
"comments": []
}
]
},
{
"id": 2,
"body": "test",
"parent_id": 1,
"comments": [
{
"id": 3,
"body": "test",
"parent_id": 2,
"comments": []
},
{
"id": 4,
"body": "test",
"parent_id": 2,
"comments": []
}
]
},
{
"id": 3,
"body": "test",
"parent_id": 2,
"comments": []
},
{
"id": 4,
"body": "test",
"parent_id": 2,
"comments": []
},
{
"id": 5,
"body": "test",
"parent_id": 1,
"comments": []
},
{
"id": 6,
"body": "test",
"parent_id": null,
"comments": []
}
]
What I would to retrive is this:
[
{
"id": 1,
"body": "test",
"parent_id": null,
"comments": [
{
"id": 2,
"body": "test",
"parent_id": 1,
"comments": [
{
"id": 3,
"body": "test",
"parent_id": 2
},
{
"id": 4,
"body": "test",
"parent_id": 2
}
]
},
{
"id": 5,
"body": "test",
"parent_id": 1,
"comments": []
}
]
},
{
"id": 6,
"body": "test",
"parent_id": null,
"comments": []
}
]
I would like that the child comments don't repeat again at top level, what can I do?
thank you.
Add whereNull(‘parent_id’) to your top level query.
return Comment::whereNull('parent_id')->with('comments.comments')->get();

filtering json data in php laravel

I've a sample json data
"regions": [
{
"id": 1,
"name": "Region 1",
"state_id": 1,
"areas" :[ {
"id": 1,
"name": "area 1",
"region_id": 1},
{
"id": 2,
"name": "area 2",
"region_id": 1}
]
},
{
"id": 2,
"name": "Region 2",
"state_id": 1,
"areas" :[ {
"id": 3,
"name": "area 3",
"region_id": 2},
{
"id": 4,
"name": "area 4",
"region_id": 2}
]
}
]
How can I filter out the data the based on id in the regions? For example, if id is 2, then the response should be like
"regions": [
{
"id": 2,
"name": "Region 2",
"state_id": 1,
"areas" :[ {
"id": 3,
"name": "area 3",
"region_id": 2},
{
"id": 4,
"name": "area 4",
"region_id": 2}
]
}
]
You can json_decode that json string and then use array_filter method to filter regions
$regions = json_decode('{"regions":
[
{
"id": 1,
"name": "Region 1",
"state_id": 1,
"areas" :[ {
"id": 1,
"name": "area 1",
"region_id": 1
},{
"id": 2,
"name": "area 2",
"region_id": 1
}]
},{
"id": 2,
"name": "Region 2",
"state_id": 1,
"areas" :[{
"id": 3,
"name": "area 3",
"region_id": 2
},{
"id": 4,
"name": "area 4",
"region_id": 2
}]
}
]
}', true);
// Filter Region
$region_id = 2;
$filtered_regions = array_filter($regions['regions'], function($r) use ($region_id) {
return $r['id'] == $region_id;
});
// Filter By Area Id
$area_id = 2;
$filtered_areas = array_filter($regions['regions'], function($r) use ($area_id) {
$areas = array_filter($r['areas'], function($area) use ($area_id) {
return $area['id'] == $area_id;
});
return count($areas) > 0;
});
return ['regions' => $filtered_regions];
First apply json_decode on your json data then apply filter . If you want to get an whole object from this response array , then write a function which will accept the id and return that object after filtering.

Yii 2 Active Record nested many to many relations

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'];
}
}

Obtaining the last level of a json tree on php

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.

json decode error on some requests but not others with Algolia php library

I'm seeing the following error:
My params are
array (size=4)
'facets' => string 'Instock.1' (length=9)
'facetFilters' => string 'inStock.1:1' (length=11)
'numericFilters' => string 'itemId!=511283' (length=14)
'getRankingInfo' => int 1
If I remove either getRankingInfo or numericFilters, it works for all requests.
According to the logs in Algolia it's returning results, but i don't get that far on my end for some requests.
One response that causes the error to appear is:
Request
{
"params": "facets=Instock.1&facetFilters=inStock.1%3A1&numericFilters=itemId%21%3D511283&getRankingInfo=1&query=WARBURTON+ORANGE+WRAPPER+800G"
}
Response
{
"hits": [
{
"itemId": 506241,
"name": "Warburton Blue Wrapper 800g",
"slug": "506241-warburton-blue-wrapper",
"brand": "Warburton",
"supplier_name": "Warburtons Bread",
"size": "800G",
"status": "L",
"vat_rate": "0.00",
"popularity": 18992,
"image": "/images/products/506241.jpg",
"thumbnail": "/images/products/506241_thumbnail.jpg",
"barcodes": [
"5010044000039"
],
"branches": [
1,
2,
4,
5,
6
],
"deepestCategory": "07013033337",
"inStock": {
"1": 1,
"2": 0,
"4": 1,
"5": 1,
"6": 1
},
"alternatives": [
],
"objectID": "506241",
"_highlightResult": {
"name": {
"value": "<em>Warburton</em> Blue <em>Wrapper</em> <em>800g</em>",
"matchLevel": "partial",
"matchedWords": [
"warburton",
"wrapper",
"800g"
]
},
"barcodes": [
{
"value": "5010044000039",
"matchLevel": "none",
"matchedWords": [
]
}
]
},
"_rankingInfo": {
"nbTypos": 0,
"firstMatchedWord": 0,
"proximityDistance": 10,
"userScore": 21542,
"geoDistance": 0,
"geoPrecision": 1,
"nbExactWords": 3,
"words": 3
}
},
{
"itemId": 511294,
"name": "Warburton Green Wrapper ",
"slug": "511294-warburton-green-wrapper",
"brand": "Warburton",
"supplier_name": "Warburtons Bread",
"size": "",
"status": "L",
"vat_rate": "0.00",
"popularity": 78098,
"image": "/images/products/511294.jpg",
"thumbnail": "/images/products/511294_thumbnail.jpg",
"barcodes": [
"5010044002347"
],
"branches": [
1,
2,
4,
5,
6
],
"deepestCategory": "07013033337",
"inStock": {
"1":
One that works fine is:
Request body
{
"params": "facets=Instock.1&facetFilters=inStock.1%3A1&numericFilters=itemId%21%3D558471&getRankingInfo=1&query=I+CAN%27T+BELIEVE+IT%27S+NOT+BUTTER+2KG"
}
Response
{
"hits": [
{
"itemId": 581691,
"name": "I Can't Believe Its Not Butter 500g",
"slug": "581691-i-cant-believe-its-not-butter",
"brand": "I Can't Believe",
"supplier_name": "U.lever Bestfoods (chilled)",
"size": "500G",
"status": "L",
"vat_rate": "0.00",
"popularity": 36597,
"image": "/images/products/581691.jpg",
"thumbnail": "/images/products/581691_thumbnail.jpg",
"barcodes": [
"000118039904",
"05000118039904",
"5000241007009"
],
"branches": [
1,
2,
3,
4,
5,
6
],
"deepestCategory": "07015269103",
"inStock": {
"1": 1,
"2": 1,
"3": 1,
"4": 1,
"5": 1,
"6": 1
},
"alternatives": [
],
"objectID": "581691",
"_highlightResult": {
"name": {
"value": "<em>I</em> <em>Can't</em> <em>Believe</em> <em>Its</em> <em>Not</em> <em>Butter</em> 500g",
"matchLevel": "partial",
"matchedWords": [
"i",
"can",
"t",
"believe",
"it",
"s",
"not",
"butter"
]
},
"barcodes": [
{
"value": "000118039904",
"matchLevel": "none",
"matchedWords": [
]
},
{
"value": "05000118039904",
"matchLevel": "none",
"matchedWords": [
]
},
{
"value": "5000241007009",
"matchLevel": "none",
"matchedWords": [
]
}
]
},
"_rankingInfo": {
"nbTypos": 0,
"firstMatchedWord": 0,
"proximityDistance": 22,
"userScore": 15914,
"geoDistance": 0,
"geoPrecision": 1,
"nbExactWords": 6,
"words": 8
}
},
{
"itemId": 247577,
"name": "I Can't Believe Its Not Butter 250g"
It seems the result set was causing an error with json_decode. When I limited the hitsPerPage to 10 all works fine. So the answer here is to paginate large sets, obvious really.
Thanks to all who read and commented.

Categories