I have three tables,
User cities user_cities
id name title id name user_id city_id
1 aaa designer 1 cityA 2 1
2 bbb developer 2 cityB 2 2
3 ccc designer 3 cityC 1 2
1 1
2 3
3 2
After joining and querying the database my result is,
data: {
0: {
id: 1
name: aaa,
title: designer,
cities :[
0: {
id: 1,
name: cityA
}
1: {
id: 2,
name: cityB
}
2: {
id: 3,
name: cityC
}
]
},
1: {
id: 2
name: bbb,
title: developer,
cities :[
0: {
id: 1,
name: cityA
}
1: {
id: 2,
name: cityB
}
]
}
1: {
id: 3
name: ccc,
title: designer,
cities :[
0: {
id: 2,
name: cityB
}
]
}
}
Everything is fine until here. But i want to groupBy by cities and take count.
If i filter by title=designer the filtered data will display and i want to make group by cities and take count of it.
So my final result will be,
cityA = 1 counts
cityC = 2 counts
Help me to solve the problem.
You might use the withCount to eager load the relationship counts.
I assume you already have the cities relationship defined in the User.php model:
class User
{
public function cities()
{
return $this->belongsToMany(City::class);
}
}
Then:
$users = User::withCount('cities')->get();
I think the results are gonna be:
data: {
0: {
id: 1
name: aaa,
title: designer,
cities_count: 3
},
1: {
id: 2
name: bbb,
title: developer,
cities_count: 2
}
1: {
id: 3
name: ccc,
title: designer,
cities_count: 1
}
}
An alternative could be using lazy eager loading:
$users = User::all()->loadCount('cities');
Related
I am trying to fetch data using groupBy method in laravel, but it's returning all data. what I am trying to get is
lets there are 2 tables
Table 1 : variants
id variant
1 color
2 size
Table 2: product_variants
color variant_id
red 1
yellow 1
red 1
sm 2
xl 2
lg 2
Now I want to fetch data so it returns as follow:
variant_table: {
id:1,
variant: color,
variants: {
variant_id: 1,
color:red
},
{
variant_id: 1,
color:yellow
}
},
{
id:2,
variant: size,
variants: {
variant_id: 2,
color:sm
},
{
variant_id: 2,
color:lg
},
{
variant_id: 2,
color:xl
}
}
But I am getting all variants instead of distincts grouped by variant_table id, My code:
$productVariants = ProductVariant::with('productVariants')
->whereHas('productVariants',function ($q) {
$q->groupBy('variant_id');
})
->get();
let suppose the model of product_variants table is ProductVariant
let suppose the model of variants table is Variant
let suppose the in model ProductVariant the relation function name is variant()
$product_variants = ProductVariant::with('variant')->groupBy('variant_id')->get();
try this $product_variants = ProductVariant::with('variant')->get()->groupBy('variant_id');
if it does not work than config\database.php --> "mysql" array
Set 'strict' => false
I started to learn GraphQL and I'm trying to create the following relationship:
type User {
id: ID!,
name: String!,
favoriteFoods: [Food]
}
type Food {
id: ID!
name: String!
recipe: String
}
So basically, a user can have many favorite foods, and a food can be the favorite of many users. I'm using graphql.js, here's my code:
const Person = new GraphQLObjectType({
name: 'Person',
description: 'Represents a Person type',
fields: () => ({
id: {type: GraphQLNonNull(GraphQLID)},
name: {type: GraphQLNonNull(GraphQLString)},
favoriteFoods: {type: GraphQLList(Food)},
})
})
const Food = new GraphQLObjectType({
name: 'Food',
description: 'Favorite food(s) of a person',
fields: () => ({
id: {type: GraphQLNonNull(GraphQLID)},
name: {type: GraphQLNonNull(GraphQLString)},
recipe: {type: GraphQLString}
})
})
And here's the food data:
let foodData = [
{id: 1, name: 'Lasagna', recipe: 'Do this then that then put it in the oven'},
{id: 2, name: 'Pancakes', recipe: 'If you stop to think about, it\'s just a thin, tasteless cake.'},
{id: 3, name: 'Cereal', recipe: 'The universal "I\'m not in the mood to cook." recipe.'},
{id: 4, name: 'Hashbrowns', recipe: 'Just a potato and an oil and you\'re all set.'}
]
Since I'm just trying things out yet, my resolver basically just returns a user that is created inside the resolver itself. My thought process was: put the food IDs in a GraphQLList, then get the data from foodData usind lodash function find(), and replace the values in person.favoriteFoods with the data found.
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
description: 'Root Query',
fields: {
person: {
type: Person,
resolve(parent) {
let person = {
name: 'Daniel',
favoriteFoods: [1, 2, 3]
}
foodIds = person.favoriteFoods
for (var i = 0; i < foodIds.length; i++) {
person.favoriteFoods.push(_.find(foodData, {id: foodIds[i]}))
person.favoriteFoods.shift()
}
return person
}
}
}
})
But the last food is returning null. Here's the result of a query:
query {
person {
name
favoriteFoods {
name
recipe
}
}
}
# Returns
{
"data": {
"person": {
"name": "Daniel",
"favoriteFoods": [
{
"name": "Lasagna",
"recipe": "Do this then that then put it in the oven"
},
{
"name": "Pancakes",
"recipe": "If you stop to think about, it's just a thin, tasteless cake."
},
null
]
}
}
}
Is it even possible to return the data from the Food type by using only its ID? Or should I make another query just for that? In my head the relationship makes sense, I don't think I need to store the IDs of all the users that like a certain food in the foodData since it has an ID that I can use to fetch the data, so I can't see the problem with the code or its structure.
Calling shift and push on an array while iterating through that same array will invariably lead to some unexpected results. You could make a copy of the array, but it'd be much easier to just use map:
const person = {
name: 'Daniel',
favoriteFoods: [1, 2, 3],
}
person.favoriteFoods = person.favoriteFoods.map(id => {
return foodData.find(food => food.id === id)
})
return person
The other issue here is that if your schema returns a Person in another resolver, you'll have to duplicate this logic in that resolver too. What you really should do is just return the person with favoriteFoods: [1, 2, 3]. Then write a separate resolver for the favoriteFoods field:
resolve(person) {
return person.favoriteFoods.map(id => {
return foodData.find(food => food.id === id)
})
}
I have two models Cities and States. One City has 1 State and one State can have 0 or more Cities. I need to retrieve all Cities and States separately because I need to display states even if a state has no related cities (like Alabama in the below example). The issue is I need to sort by State name first, and than by Cities in that state (if there are any)
Cities
id, state_id, name
1, 1, San Diego
2, 1, Hollywood
3, 2, Seattle
4, 3, Pheonix
States
id, name
1, California
2, Washington
3, Arizona
4, Alabama
Controller:
$cities = Cities::with('state')->get(); // Returns the state relationship
$states = States::get();
$merged = $states->merge($cities);
I would now like to sort by State name first, and then all the cities in that State and return a merged collection similar to this:
{
id: 4,
name: Alabama,
},
{
id: 3,
name: Arizona,
},
{
id: 3,
name: Pheonix,
state_id: 3
state: {
id: 3,
name: Arizona
}
},
{
id: 1,
name: California
},
{
id: 2,
name: Hollywood
state_id: 1,
state: {
id: 1,
name: California
}
},
{
id: 1,
name: San Diego,
state_id: 1,
state: {
id: 1,
name: California
}
},
{
id: 2,
name: Washington,
},
{
id: 2,
name: Seattle,
state_id: 2,
state: {
id: 2,
name: Washington
}
}
I think you could do a query like this:
$states = State::all()->sortBy('name'); // Here your sort by the state name first
If you made the relations right you can access the cities from each state like this: (you dont need to merge collections):
#foreach($states as $state) // this will sort the cities by id
{{$state->cities}}
#endforeach
To sort them by the name you could try this:
#foreach($states as $state)
{{$state->cities->sortBy('name')}}
#endforeach
So I have 2 models Books and Classes:
$books = Books::limit(3)->get(['id','classable_id','easy_book']);
// Books returned:
{ id: 200,
classable_id: 2,
easy_book: false
},
{ id: 201,
classable_id: 3,
easy_book: true
},
{ id: 202,
classable_id: 4,
easy_book: false
}
$classIds = $books->pluck('classable_id');
$classes = Classes::whereIn('id', $classIds);
// Classes returned:
{ id: 2,
subject: Math,
students: 30
},
{ id: 3,
subject: History,
students: 30
},
{ id: 4,
subject: Physics,
students: 30
}
Then trying to get the following output (without combining the queries, but keeping them separate like above, and just using php logic to output):
Classes returned:
{ id: 2,
subject: Math,
students: 30.
easy_book: false }, // trying to merge this!
{ id: 3,
subject: History,
students: 30.
easy_book: true}, // trying to merge this!
{ id: 4,
subject: Physics,
students: 30.
easy_book: false } // trying to merge this!
Basically, I am trying to merge the easy_book field from books returned to the respective class returned based on class.id == books.classable_id. Any idea how to merge it?
Add a relationship to your Books model like so:
public function class() {
return $this->belongsTo(Classes::class, 'id', 'classable_id);
}
Then you can do:
Book::with('class')->select('id', 'classable_id', 'easy_book')->limit(3)->get();
Each collection item will then have a collection of classes where applicable.
If after that you want to manipulate them, you can use the map function as documented here: https://laravel.com/docs/5.7/collections#method-map
I have a postgres table that represents a hierarchy with a parent child table:
Table (Categories):
id name parentId
1 CatA null
2 CatB null
3 CatC 1
4 CatD 1
5 CatE 3
desired result:
categories:
[
{
name: "CatA",
children: [
{
name: "CatC",
children: [
{
name: "CatE",
children: []
}]
},
{
name: "CatD",
children: []
}
],
},
{
name: "CatB",
children: []
}
]
The problem is that I don't know how many levels there are, so I can't query something like:
category {
name
parent {
name
parent {
name
...
You can actually achieve the potential infinite recursion with GraphQL. So it doesn't mind if you don't know how deep you go with your schema.
I was able to reproduce your desired result with this schema. I hope it might helps you:
const categories = [
{
name: 'CatA',
children: [
{
name: 'CatC',
children: [
{
name: 'CatE',
children: []
}]
},
{
name: 'CatD',
children: []
}
]
},
{
name: 'CatB',
children: []
}
];
const categoryType = new GraphQLObjectType({
name: 'CategoryType',
fields: () => ({
name: { type: GraphQLString },
children: { type: new GraphQLList(categoryType) }
})
});
const queryType = new GraphQLObjectType({
name: 'RootQuery',
fields: () => ({
categories: {
type: new GraphQLList(categoryType),
resolve: () => categories
}
})
});
And I got this result:
Please notice that I define field property as a function rather than an plain object. The field property defined as object would failed and wouldn't allow you to use categoryType variable in the fields, because in the time of execution it doesn't exist.
fields: () => ({
...
})
One of the difficulties of using GraphQL on top of a SQL database is reconciling the two paradigms. GraphQL is hierarchical. SQL databases are relational. There isn't always a clear mapping between the two.
We open-sourced a framework, Join Monster, that has an opinionated way of setting up your schemas. If you do so, it automatically generates the SQL queries for you. It was built with the idea of relations in its core. In theory you can achieve arbitrary depth in your GraphQL queries.