Can I directly get a nested list in my Doctrine result? - doctrine

Sorry if the question is poorly phrased, I couldn't come up with a good way of describing my issue.
So basically, I'm using the Doctrine query builder to try and a list of training sessions from my Session entity. For each session, I need to fetch basic properties such as the name and date, but I also need to fetch the list of participants. There is a one-to-many relation between the entities Session and Participant, as there may be several participants to a given session. I would simply need a list of these participants, nested in each item of the list of sessions. Something like this:
[
{
"session_name": "name1",
"session_date": "date1",
...
"participants": [
{
"participant_name": "john1",
...
},
{
"participant_name": "john2",
...
},
...
],
},
{
"session_name": "name2",
"session_date": "date2",
...
"participants": [
{
"participant_name": "john3",
...
},
{
"participant_name": "john4",
...
},
...
],
},
...
]
This seems to me like it should be quite basic, but for the life of me I cannot get it to work with JOINs, subqueries, etc. The closest I got was this error, which does imply I'm trying to get a nested array (but it won't let me):
SQLSTATE[21000]: Cardinality violation: 1242 Subquery returns more than 1 row
I had this error running this code:
$query = $this->createQueryBuilder('s')
->select('
s.name,
s.date,
(SELECT p.nom FROM '.Participant::class.' p WHERE p.session = s.id) participants
')
->getQuery()->getArrayResult();
I know I could just fetch my sessions, then loop through them and fetch their participants with another DQL query, but obviously that doesn't seem like the proper way to do it. Is there a better way?

You can directly do a leftJoin on your QueryBuilder :
$queryResult = $this->createQueryBuilder('s')
// After that next line, you can reference participants as 'p'
->leftJoin('s.participants', 'p')
// If you intend to loop on the result, to avoid the N+1 problem, add this line :
->addSelect('p')
->getQuery()
->getResult()
;

Related

how to keyBy in laravel as string

I know for a fact that in laravel if I want to get eloquent results with id as key i do this:
$users = \App\Models\User::all()->keyBy('id');
and if I want to loop through it with javascript I do as this:
for (const key in users) {
..}
the problem is that since I used id as key now looping through ignores the date order of results (specially if I use pagination that would be a great headache). Is there any way to stringify id before returning results to client side, so javascript loop through on the date order of results?
I mean something like this:
users = {
"1" : {
"id":1,
name: "blah blah",
..
}
..
}

Query does not return some items from DynamoDB via GraphQL

May I please know what is the reason why are items in DynamoDB not being fetched by GraphQL?
When searching via the DynamoDB console interface, I could easily see and query the item in there but once used in GraphQL, some items are not showing. Mind you, this isn't a connection problem because I could query items its just there's a specific item that is not being returned.
For example, if I query all Posts, it will return all posts in an array but the item is not showing there. However, when I try to query a Post just by targetting it by its ID, it is working well.
Example code that is not working:
listPosts(filter: {groupID: {eq: "25"}}) {
items {
id
content
}
}
but when I do this, it is working well:
getPost(id: "c59ce7e9") {
id
content
}
I had this same issue and can share what i found and worked for me.
The default resolver for the list operation has a limit:20 built in.
{
"version": "2017-02-28",
"operation": "Scan",
"filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end,
"limit": $util.defaultIfNull($ctx.args.limit, 20),
"nextToken": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.nextToken, null)),
}
I imagine you could change this or you could add a limit filter to your query like this:
listPosts(filter: {groupID: {eq: "25"}}, limit:100) {
items {
id
content
}
}
The limit should be higher than the number of records.
You can see that this would be an issue because it is using the scan operation meaning it inspects each record for a match. this would hurt performance. you could add pagination or you should craft a query for this. you will need to look into pagination, relations and connection.
https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html#advanced-relations-and-pagination

How to implement a partial resource rest api?

In order to limit the size of my REST API answers, I want to implement the Google performance tip: using the fields query string parameter to do partial resources.
If I have a full answer GET https://myapi.com/v1/users
[
{
"id": 12,
"first_name": "Angie",
"last_name": "Smith",
"address": {
"street": "1122 Something St.",
"city": "A city"
..and so on...
}
},
... and so on
]
I will be able to filter it GET https://myapi.com/v1/users?fields=first_name
[
{
"id": 12,
"first_name": "Angie"
},
... and so on
]
The concept is pretty easy to understand, but I can't find an easy way to implement it!
My API resources are all design the same way:
use query string parameters for filtering, sorting, paging.
call a service with that parameters to do a SQL request (only the WHERE condition, the ORDER BY condition and the LIMIT are dynamic)
use a converter to format data back to JSON
But when using this new fields parameter, what do I need to do? where do I filter the data?
Do I need to filter only the JSON output? But I will make (in that example) an unwanted JOIN query on address table and fetch unwanted fields in the users table.
Do I need to make a dynamic SQL query to fetch exactly the requested fields and add the JOIN only when the end user need it? Then the converter will have to be smart to convert only the available fields in the SQL query.
In my opinion, this second solution will produce a code extremely dynamic, extremely complex and difficult to maintain.
So, how do you implement such REST API with partial resource feature? What are you best practice in that case?
(I'm a PHP developer, but I don't think it's relevant for that question)
If your backend is doing
GET https://myapi.com/v1/users
which results in SQL:
select * from users
which you then turn into JSON, can you not just do:
GET https://myapi.com/v1/users?fields=first_name,surname,email
get all the required fields (rough idea of PHP implementation):
$fields = split(",", $_GET["fields"]);
$sql = "select ";
foreach ($fields as &$field) {
// do a check to see if the field is ok first...
if (checkField($field)) {
$sql += field + "," // deal with commas
}
}
$sql += " from users";
to build SQL like:
select firstname,surname,email from users
and turn that limited dataset to JSON?

Filter documents based on value of an attribute inside an array of objects

RethinkDB newb here and I can't figure this one out.
Lets say I have a table named mydata with documents that have the following basic structure:
{
"SomeAttirbute": "SomeValue",
"team": [
{
"name": "john" ,
"other": "stuff",
} ,
{
"name": "jane" ,
"other": "junk",
}
] ,
...
}
How do I get all documents in the mydata table that have john for a value of the name attribute for any of the elements in the team array?
This is pretty easy and requires a simple ReQL expression. In JavaScript it would be something like this:
const name = 'john';
...
r.db('q50732045')
.table('mydata')
// The predicate below can be literally read as:
// a document whose `team` property is a sequence
// that contains any element with a property `name`
// that equals the given name
.filter(doc => doc('team').contains(member => member('name').eq(name)))
// No need to invoke the run method in Data Explorer
;
I do believe it can be easily re-written in Python.
I think this is what you are looking for:
r.db(insert_database_name).table("mydata").filter(
lambda doc: doc["team"]["name"].contains("john")
).run(con)
or:
r.db(insert_database_name).table("mydata").filter(
r.row["team"]["name"].contains("john")
).run(con)

Laravel Eloquent: how to add a column to a query response?

In other words, lets say i have a query like that:
return Location::valid()
->with('owners', 'gardeners')
->withCount('gardeners')
->get();
that returns some json :
[
{
name: 'LocationA',
nb_gardeners_max: 3,
owners: [...],
garderners: [...],
garderners_count: 2
}
]
in the json response i'd like to add some custom entry like is_full and available_places:
[
{
name: 'LocationA',
nb_gardeners_max: 3,
owners: [...],
garderners: [...],
garderners_count: 2,
...
is_full: false,
available_places: 1
}
]
I guess it has something to do with raw / join / aggregate... but i really don't understand how to do so. Any help will be greatly appreciated
EDIT
Minhajul answer is really usefull but it's not possible to do a WHERE clause on the appended attribute.
Location::where('is_full',true)->get() // NOT WORKING
Though it's still possible to do filter() on it, I'd like to use a JOIN for that to perform a single query
To do so, you can add attributes that do not have a corresponding column in your database.To do this, all you need to modify your model
public function getIsFullAttribute()
{
return $this->attributes['name'] == 'value';
}
After creating this accessor, you need to add this in your model.
protected $appends = ['is_full'];
Hopefully, it will help you.

Resources