Inner join in JPA using native query - spring-boot

I have two tables -
Podcasts
Categories
Podcast columns - podcast_id, podcast_autho, podcast_category_id, podcast_description, podcast_owner, podcast_subcategory_id, podcast_title
Category columns - category_id, category_name, category_owner
podcast_category_id has a value from the Categories table and so does podcast_subcategory_id.
Now, I have an SQL statement which inner joins the two table to produce category name instead of id in the output -
SELECT p.*, c.category_name, c2.category_name AS sub_category_name FROM podcasts p
LEFT JOIN categories c ON p.podcast_category_id = c.category_id
LEFT JOIN categories c2 ON p.podcast_subcategory_id = c2.category_id;
I use the same query in my JpaRepository class to get the output -
interface PodcastRepository: JpaRepository<Podcast, Long> {
#Query(value = "SELECT p.*, c.category_name, c2.category_name AS sub_category_name FROM podcasts p " +
"LEFT JOIN categories c ON p.podcast_category_id = c.category_id " +
"LEFT JOIN categories c2 ON p.podcast_subcategory_id = c2.category_id",
nativeQuery = true)
fun getPodcastsByOwner(owner: Long): List<Any>
}
I do get an output but it is not in JSON format unlike other cases where I don't user Any (Object in Java) but the specific Entity class.
What I get -
[
[
8,
"krktush",
2,
"World War 1",
1,
3,
"What Went Wrong",
"General",
"Specific"
],
[
9,
"krktush",
2,
"World War 2",
1,
3,
"What went right",
"General",
"Specific"
]
]
What I expect -
[
{
"id": 16,
"author": "krtkush",
"title": "World War 1",
"description": "What Went Wrong",
"category": "2",
"subCategory": "",
"owner": 1,
"categoryName": General,
"subCategoryName": Specific
},
{
"id": 22,
"author": "krtkush",
"title": "World War 2",
"description": "What Went Right",
"category": "20",
"subCategory": "",
"owner": 1,
"categoryName": General,
"subCategoryName": Specific
}
]
How do I achieve this?

Related

DRF Serailze Parent-Child Relation models

I have Parent-Children Relation Table in Model which is as follows:
models.py
class ProductCategory(models.Model):
parent = models.ForeignKey(to='ProductCategory', blank=True, null=True, related_name="sub_cats", on_delete=models.CASCADE)
name = models.CharField(max_length=30, blank=False, null=False)
desc = models.TextField(blank=True, null=True, db_column='description')
def __str__(self):
return self.name
Data in table
Using this data I want to make a tree in react component where a user see how many types of categories a product has.
right now getting this
[
{
"id": 1,
"parent": null,
"name": "Electronics",
"desc": "All kinds of electronics items comes in this category",
"sub_cats": [
{
"id": 2,
"parent": 1,
"name": "Mobiles",
"desc": "Category for Smartphones, Features-Phone, etc.",
"sub_cats": [3]
}
]
},
{
"id": 2,
"parent": 1,
"name": "Mobiles",
"desc": "Category for Smartphones, Features-Phone, etc.",
"sub_cats": [
{
"id": 3,
"parent": 2,
"name": "X-Mobile",
"desc": "All Smartphones of X-Mobile",
"sub_cats": []
}
]
},
{
"id": 3,
"parent": 2,
"name": "X-Mobile",
"desc": "All Smartphones of X-Mobile",
"sub_cats": []
}
]
or any other idea for making tree

How to get data by query builder in laravel

I use join in query builder and here is the output
[
{
"id": 7,
"name": "class 1",
"idSubject": 17,
"nameSubject": "Math"
},
{
"id": 7,
"name": "class 1",
"idSubject": 16,
"nameSubject": "history"
},
{
"id": 8,
"name": "class 2",
"idSubject": 15,
"nameSubject": "Computer"
},
{
"id": 8,
"name": "class 2",
"idSubject": 19,
"nameSubject": "geography"
}
]
You can see id and name of class 1, 2 appearing twice. So, how to make it appear once.
this is my query:
$data = DB::table('class')->join('class_subject','class.id','=','class_subject.class_id')
->join('subject','class_subject.subject_id','=','subject.id')
->select('class.id','class.name','subject.id as idSubject','subject.name as nameSubject') ->get();
I want it:
[
{
"id": 7,
"name": "class 1",
"subject": [{"idSubject":"17","nameSubject: "Math"},
{"idSubject":"16","nameSubject: "history"}]
}
]
The distinct method allows you to force the query to return distinct results:
Try this
$data = DB::table('class')->join('class_subject','class.id','=','class_subject.class_id')
->join('subject','class_subject.subject_id','=','subject.id')
->select('class.id','class.name','subject.id as idSubject','subject.name as nameSubject')->distinct()->get();

Trying to get foraign key records where every connected records are deactive ( Laravel elequent query )

I have 2 tables
Category's ( id, name )
Sub_categories ( id, key, value, category_id )
I'm trying to get all Category's whose all sub_categories are deactivated ( means are soft-deleted )
let me explain more
i have sub_categories data like this
[
{
"id": 1,
"category_id": 1,
"key": "sub 1",
"value": "sub_1",
"deleted_at": null
},
{
"id": 2,
"category_id": 1,
"key": "sub 2",
"value": "1",
"deleted_at": null
},
{
"id": 4,
"category_id": 1,
"key": "sub 3",
"value": "1",
"deleted_at": "2019-07-09 06:06:01"
},
{
"id": 5,
"category_id": 2,
"key": "sub 1",
"value": "33",
"deleted_at": "2019-07-09 06:06:01"
},
{
"id": 6,
"category_id": 2,
"key": "sub 2",
"value": "33",
"deleted_at": "2019-07-09 06:06:01"
}
]
i want only category_id -> 2 ( where all sub_categories are softedeleted )
hear's category model code
public function subCategory() {
$this->makeVisible('deleted_at');
return $this->hasMany('App\SubCategory','category_id','id');
}
$categories = Categories::doesntHave('subCategory')->get();
you first have to define Relationship between Categorys and Sub_categories - https://laravel.com/docs/5.8/eloquent-relationships.
Then use query to get what you want https://laravel.com/docs/5.8/queries
Get IDs of categories with sub categories:
$categoryIdsWithSubCategories = SubCategory::get()->pluck('category_id')->toArray();
Get categories without sub categories:
$categoriesWithoutSubCategories = Category::whereNotIn('id', $categoryIdsWithSubCategories)->get();

CosmosDB - SubDocument Delselecting - LINQ Query

I have a ProductDocument model in CosmosDB, which represents a Product. Within that model there is a subdocument contributors which holds who has contributed to the Product. Each contributor has a role.
Now I have been experimenting with a query that needs to:
Only select ProductDocument with a contributor.roleDescription of Author
Only select ProductDocument with a division of Pub 1
Only include contributors sub documents with a contributor.roleDescription of Author in the result set.
Now I'm struggling with:
Part 3 of select above. How do I accomplish this bit as my result set is including both contributor.roleDescription of Author AND Illustrator
Example Cosmos Model:
[
{
"id": "1",
"coverTitle": "A Title",
"pubPrice": 2.99,
"division" :"Pub 1",
"Availability": {
"code": "20",
"description": "Digital No Stock"
},
"contributors": [
{
"id": 1,
"firstName": "Brad",
"lastName": "Smith",
"roleDescription": "Author",
"roleCode": "A01"
},
{
"id": 2,
"firstName": "Steve",
"lastName": "Bradley",
"roleDescription": "Illustrator",
"roleCode": "A12"
}
]
},
{
"id": "2",
"coverTitle": "Another Title",
"division" :"Pub 2",
"pubPrice": 2.99,
"Availability": {
"code": "50",
"description": "In Stock"
},
"contributors": [
{
"id": 1,
"firstName": "Gareth Bradley",
"lastName": "Smith",
"roleDescription": "Author",
"roleCode": "A01"
}
]
}]
Here is my SQL which I have been playing around with in the Data Explorer:
SELECT VALUE p
FROM Products p
JOIN c IN p.contributors
WHERE c.roleDescription = 'Author'
AND p.division = 'Pub 1'
Here is my LINQ query from my service:
var query = client.CreateDocumentQuery<ProductDocument>(
UriFactory.CreateDocumentCollectionUri("BiblioAPI", "Products"),
new FeedOptions
{
MaxItemCount = -1,
EnableCrossPartitionQuery = true
}
)
.SelectMany(product => product.Contributors
.Where(contributor => contributor.RoleDescription == "Author")
.Select(c => product)
.Where(p => product.Division == "Pub 1"))
.AsDocumentQuery();
List<ProductDocument> results = new List<ProductDocument>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<ProductDocument>());
}
It selects the correct records, but how do I de-select the Illustrator sub document of contributor, because at the moment I get the following:
{
"id": "1",
"coverTitle": "A Title",
"pubPrice": 2.99,
"division" :"Pub 1",
"Availability": {
"code": "20",
"description": "Digital No Stock"
},
"contributors": [
{
"id": 1,
"firstName": "Brad",
"lastName": "Smith",
"roleDescription": "Author",
"roleCode": "A01"
},
{
"id": 2,
"firstName": "Steve",
"lastName": "Bradley",
"roleDescription": "Illustrator",
"roleCode": "A12"
}
]
}
But the following output is what I want, excluding the Illustrator contributor sub document:
{
"id": "1",
"coverTitle": "A Title",
"pubPrice": 2.99,
"division" :"Pub 1",
"Availability": {
"code": "20",
"description": "Digital No Stock"
},
"contributors": [
{
"id": 1,
"firstName": "Brad",
"lastName": "Smith",
"roleDescription": "Author",
"roleCode": "A01"
}
]
}
EDIT:
I would like to filter on Product if one of the subdocument contributor.roleDescription equals Author. So if the Product record doesn't include a Author contributor I don't want it
I want to include each contributor subdocument that equals Author. So if there are multiple Author contributor subdocuments for a Product, I want to include them, but exclude the Illustrator ones.
You could have a Collection of ProductDocuments.
Help on the fluent LINQ syntax would help greatly.
Azure CosmosDB now supports subqueries. Using subqueries, you could do this in two ways, with minor differences:
You could utilize the ARRAY expression with a subquery in your projection, filtering out contributors that you don’t want, and projecting all your other attributes. This query assumes that you need a select list of attributes to project apart from the array.
SELECT c.id, c.coverTitle, c.division, ARRAY(SELECT VALUE contributor from contributor in c.contributors WHERE contributor.roleDescription = "Author") contributors
FROM c
WHERE c.division="Pub 1"
This assumes that you need to filter on division "Pub 1" first followed by the subquery with the ARRAY expression.
Alternately, if you want the entire document along with the filtered contributors, you could do this:
SELECT c, ARRAY(SELECT VALUE contributor from contributor in c.contributors WHERE contributor.roleDescription = "Author") contributors
FROM c
WHERE c.division="Pub 1"
This will project the original document with a "Pub 1" division in the property labeled "c", along with a filtered contributor array separately in the property labeled "contributors". You could refer this contributor array for your filtered contributors and ignore the one in the document.
This will do what you want, but obviously if you have multiple contributors you want to show it might not do quite what you are after - it's hard to tell with your question if that is what you want exactly
SELECT p.id, p.coverTitle, p.pubPrice, p.division, p.Availability, c as contributors
FROM Products p
JOIN c IN p.contributors
WHERE c.roleDescription = 'Author'
AND p.division = 'Pub 1'
and the output is:
[
{
"id": "1",
"coverTitle": "A Title",
"pubPrice": 2.99,
"division": "Pub 1",
"Availability": {
"code": "20",
"description": "Digital No Stock"
},
"contributors": {
"id": 1,
"firstName": "Brad",
"lastName": "Smith",
"roleDescription": "Author",
"roleCode": "A01"
}
}
]
Note that contributors is not a list, it's a single value, so if multiple contributors match the filter, then you will get the same product returned multiple times.

How do you perform projections in RethinkDB?

Given the following data in two tables:
Employees
[
{"name": "person 1", "dept": 1},
{"name": "person 2", "dept": 1},
{"name": "person 3", "dept": 2}
]
Departments
[
{"name": "design", "id": 1},
{"name": "development", "id": 2}
]
To run a query with a join:
r.db('mydb').table('employees').eqJoin('dept', r.db('mydb').table('departments')).zip();
This will merge the results and I end up with a single 'name' property from the departments overwriting the name from the employees table.
How to you handle projections in RethinkDB to handle this to that I can end up with the name from both the Employee and Department tables?
You can manually map
r.db('mydb').table('employees')
.eqJoin('dept', r.db('mydb').table('departments'))
.map(function(doc) {
return {
personName: left("name"),
departmentName: right("name"),
// etc.
}
})

Resources