After reading through documentation I can't find anything about how to make this simple query:
there is two tables:
first one is "PACKAGES"
{
id: 1,
name: 'package_1',
sender_id: 1,
type: 'shipping'
}
second one is "USERS"
{
id: 1,
name: 'user_1'
}
When I perform Left, Right Join, or simply JOIN, its just merges this two tables into one. And id, name just overwrites with each other
What I need is:
{
id: 1,
name: 'package_1',
sender_id: 1
type: 'shipping',
user: { // second table as nested object
id: 1,
name: 'user_1'
}
}
I tried everything that I can find, for example:
SELECT * FROM packages JOIN users AS user ON packages.sender_id=user.id;"
How I can put right table as an object inside left table?
Use to_json to present the query result as a nested JSON object:
select to_json(res) from
(
select p.*, to_json(u) "user"
from packages p
inner join users u
on p.sender_id = u.id
) res;
Result:
{
"id": 1,
"name": "package_1",
"sender_id": 1,
"type": "shipping",
"user": {
"id": 1,
"name": "user_1"
}
}
Related
I have 3 tables sale,company and saleItem with the following relations:
Sale.belongsTo(Company);
Company.hasMany(Sale);
Sale.hasMany(SaleItem, { as: "items" });
SaleItem.belongsTo(Sale);
I want to apply a filter on the company's name I saw that to do that we have to use $ at the start and end but it isnt working. Any ideas where I am going wrong?
When I try to execute the below code I get the error:
SqlError: (conn=201, no: 1054, SQLState: 42S22) Unknown column 'company.name' in 'where clause'
sql: SELECT `sale`.*, `company`.`id` AS `company.id`, `company`.`name` AS `company.name`, `items`.`id` AS `items.id`, `items`.`quantity` AS `items.quantity`, `items`.`price` AS `items.price`, `items`.`description` AS `items.description`, `items`.`margin` AS `items.margin`, `items`.`gst` AS `items.gst`, `items`.`createdAt` AS `items.createdAt`, `items`.`updatedAt` AS `items.updatedAt`, `items`.`saleId` AS `items.saleId`, `items`.`itemId` AS `items.itemId` FROM (SELECT `sale`.`id`, `sale`.`date`, `sale`.`type`, `sale`.`description`, `sale`.`poNumber`, `sale`.`poDate`, `sale`.`paymentType`, `sale`.`gst`, `sale`.`discount`, `sale`.`freight`, `sale`.`status`, `sale`.`saleStatus`, `sale`.`referenceNumber`, `sale`.`ftn`, `sale`.`quotationNumber`, `sale`.`showGST`, `sale`.`invoiceDate`, `sale`.`hasWithholdingTax`, `sale`.`serialNumber`, `sale`.`currency`, `sale`.`createdAt`, `sale`.`updatedAt`, `sale`.`companyId`, `sale`.`customerId` FROM `sale` AS `sale` WHERE `company`.`name` LIKE '%%' AND `sale`.`customerId` = 1 AND `sale`.`status` = 'ACTIVE' ORDER BY `id` DESC LIMIT 0, 15) AS `sale` LEFT OUTER JOIN `company` AS `company` ON `sale`.`companyId` = `company`.`id` LEFT OUTER JOIN `saleItem` AS `items` ON `sale`.`id` = `items`.`saleId` ORDER BY `id` DESC;
It works if I dont include the SaleItem table in query
Here is the code
await Sale.findAndCountAll({
include: [
{
model: Company,
attributes: ["name"],
as: "company",
},
{ model: SaleItem, as: "items" },
],
distinct: true,
where: {
"$company.name$": { [Op.like]: `%${search}%` },
customerId:1,
status: "ACTIVE",
},
})
If you see the generated SQL, company.name WHERE clause is incorrectly added to a subquery, so you can either turn off the subquery or you can add your where option within the include.
Option 1:
await Sale.findAndCountAll({
...,
subQuery: false
})
Option 2:
await Sale.findAndCountAll({
include: [
{
model: Company,
attributes: ["name"],
as: "company",
where: {
name: { [Op.like]: `%${search}%` }
}
},
{ model: SaleItem, as: "items" },
],
distinct: true,
where: {
customerId:1,
status: "ACTIVE",
},
})
I have 3 tables:
"tags"
id serial
name text
"questions"
id serial
content jsonb
"questions_tags" (many-to-many)
question_id integer
tag_id integer
I can select all data from questions:
SELECT * FROM questions;
I can select tags of specific question:
SELECT t.*
FROM tags t
JOIN questions_tags qt ON t.id = qt.tag_id
JOIN questions q ON qt.question_id = q.id
WHERE q.id = 157;
I need to select all questions and add to this selection tags for every question.
I'm using nodejs and node-postgres and I need to get something like:
[
{
id: 1,
content: { someProp: 'someValue' },
tags: [
{ id: 58, name: 'sometag58' },
{ id: 216, name: 'sometag216' }
]
},
...
]
How can I do this without ORM, only with the help of vanilla SQL?
I would let PostgreSQL handle it for me:
with tagjson as (
select q.id, q.content, jsonb_agg(to_jsonb(tags)) as tags
from questions q
left join questions_tags qt on qt.question_id = q.id
left join tags on tags.id = qt.tag_id
group by q.id, q.content
)
select jsonb_pretty(jsonb_agg(to_jsonb(tagjson))) as result
from tagjson;
Result:
[
{
"id": 1,
"tags": [
{
"id": 58,
"name": "sometag58"
},
{
"id": 216,
"name": "sometag216"
}
],
"content": "some question 1 content"
}
]
db<>fiddle here
EDIT TO ADD:
Based on a conversation in the comments, the final query should be modified to:
select * from tagjson;
Or the CTE could be promoted to be a stand-alone query.
This allowed the conventional node syntax while preserving the aggregated tags array under the tags key:
const questions: Question[] = result.rows;
I want to select articles containing certain category I'm using typeorm ( SQL )
let's imagine i have
articleTable: [
{
id: 1,
title: 'string'
},
{
id: 2,
title: 'string'
}
];
categoryTable: [
{
id: 1,
title: 'string'
}, {
id: 2,
title: 'string'
}
]
article_categories: [
{
categoryId: 1,
articleId: 2
},{
categoryId: 1,
articleId: 1
},{
categoryId: 2,
articleId: 2
}
]
so the question is I want to select all articles that have exactly category = [1,2] and more
that means if an article has only category 1 I don't want to select it.
using this query I'm getting results but its not exact match of ids but instead it returns articles that have id 1 and 2 separately
async filterData(filterArticleDto: FilterArticlesDto, categoryIds: number[]) {
const qb = this.createQueryBuilder('article');
qb.distinct(true);
if (categoryIds.length) {
qb.innerJoin(
'article.categories',
'categories',
`categories.category IN (:...ids)`,
{
ids: categoryIds,
},
);
qb.leftJoinAndSelect('categories.category', 'catsData');
}
qb.take(filterArticleDto.limit);
return await qb.getMany();
}
raw sql query
SELECT article.*
FROM articles AS article
WHERE EXISTS
(SELECT count(DISTINCT category_id)
FROM article_categories AS subcts
WHERE subcts.article_id = article.id
AND subcts.category_id IN (1,
2)
HAVING count(DISTINCT category_id) = 2)
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=86f8d3a8bdc9248a918a4c37d8da5ea0
OR
SELECT article.*
FROM articles AS article
INNER JOIN
(SELECT article_id,
array_agg(category_id) AS cts
FROM article_categories
GROUP BY article_id) AS category ON article.id = category.article_id
WHERE ARRAY[1,
2::integer] = category.cts
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=fdde52c1d11d69b690f9fe9345272786
Hello I need to convert this Sequelize Query to bigQuery sql Query syntax.
Comment.findAll({ where: {artifact_id: id, parent_id: null},
include: [
{ model: db.User, attributes: ['id','first_name', 'last_name'] },
{ model: db.artifact, attributes: ['id','original_artifact_name'] },
{ model: db.status, attributes: ['id','status_name'] },
{ model: Comment, as: 'replies', include: [{ model: db.User, attributes: ['id','first_name', 'last_name'] }] }
]
})
Can any one help with this ?
When I do left join of any table like this
SELECT a.*, b.group_name as parent_grp_name, c.org_name as parent_org_name
FROM ${DB}.groups a LEFT JOIN ${DB}.groups b ON b.id = a.parent_group_id
LEFT JOIN ${DB}.organizations c ON c.id = a.organization_id
ORDER BY a.created_at
LIMIT ${limit}
OFFSET ${offset}`
it gives me record as a single object with both tables data in it. I want to get joined table data as seperate object.
Goal:
This sql and its result should be the same result from mongoDB's query code.
In order words, same result but for mongoDB.
Problem:
How to you make a lookup connection in relation to People and Role in Mongo DB's query code?
Info:
I'm new in mongo DB
SQL code
SELECT
a.*,
'.' AS '.',
b.*,
'.' AS '.',
c.*
FROM
[db1].[dbo].[People_Course_Grade] a
INNER JOIN [db1].[dbo].[People] b on a.PeopleId = b.PeopleId
INNER JOIN [db1].[dbo].[Role] c on b.RoleId = c.RoleId
Json data:
Role:
[{"RoleId":1,"Name":"Student"},{"RoleId":2,"Name":"Teacher"}]
People_Course_Grade:
[{"People_Course_GradeId":1,"PeopleId":1,"CourseId":1},
{"People_Course_GradeId":2,"PeopleId":2,"CourseId":1},
{"People_Course_GradeId":3,"PeopleId":3,"CourseId":2},
{"People_Course_GradeId":4,"PeopleId":1,"CourseId":2}]
Course:
[{"CourseId":1,"Name":"Java"},{"CourseId":2,"Name":"Java II"},
{"CourseId":3,"Name":"Statistik 1"}]
db.People_Course_Grade.aggregate([
{
$lookup:{
from: "People",
localField: "people_id",
foreignField: "_id",
as: "people"
}
},
{ $unwind:"$people" },
{
$project:{
course_id : 1,
people_id : 1,
// grade_id : 1,
Name : "$people.Name",
}
}
]);
You need to start with double $lookup since you have three collections. Then you can use $arrayElemAt to always get single element from lookup's result. To flatten your structure you can use $replaceRoot with $mergeObjects (promotes all the fields from people and course to root level.
db.People_Course_Grade.aggregate([
{
$lookup:{
from: "Role",
localField: "PeopleId",
foreignField: "RoleId",
as: "people"
}
},
{
$lookup:{
from: "Course",
localField: "CourseId",
foreignField: "CourseId",
as: "course"
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
{ $arrayElemAt: [ "$people", 0 ] },
{ $arrayElemAt: [ "$course", 0 ] },
]
}
}
},
{
$project: {
people: 0,
course: 0
}
}
])
Mongo Playground
$arrayElemAt can always be replaced with $unwind like you tried. You also have a naming conflict on name field so probably you need to run $project to rename one of those fields - otherwise you'll get only one of them in final result.