Orientdb query child - sql

Is there a way with Orientdb 2.1.11 (document database) to get the EmebeddedList
Here is the class structure
{
"#class":"Quote",
"number":"Q1",
"details":[{
"code":"123",
"price":10
},{
"code":"456",
"price":20
}
]
},{
"#class":"Quote",
"number":"Q2",
"details":[{
"code":"789",
"price":15
},{
"code":"951",
"price":25
}
]
}
I would like a query that will return the following :
number| code | price
------|------|------
Q1 | 123 | 10
Q1 | 456 | 20
Q2 | 789 | 15
Q2 | 951 | 25

I have replicated your structure
and I have used this query
select number, details.code as code, details.price as price from (select prop.number as number, prop.details as details from (select prop from test unwind prop) unwind details)
Hope it helps

Related

how to obtain objects in objects (with all the key names) in SQL?

my database contains two tables named category and sport:
category
-----------------------------------
id | title | ...
1 | summer
2 | autumn
3 | spring
4 | winter
sport
--------------------------------------------------------------
id | title | description | category_id | ...
1 | ski | ... | 4
2 | surf | ... | 1
3 | snorkeling | ... | 1
4 | running | ... | 3
5 | hiking | ... | 2
...
my question is how to obtain with one request in Sql (postgresql) this result :
{
category: [
{
c.id: 1,
c.title: summer,
sport: [
{
s.id: 2,
s.title: surf,
},
{
s.id: 3,
s.title: snorkeling,
},
],
},
{
c.id: 2,
c.title: autumn,
sport: [
{
s.id: 5,
s.title: hiking
}
],
},
{
c.id: 3
c.title: spring,
sport: [
{
s.id: 4,
s.title: running,
}
],
},
{
...
}
]
}
I've tried with ARRAY_AGG but it removes the key_names and i need it to call the values with in my API.
You need to combine jsonb_agg(), to_jsonb()andjsonb_build_object()`
select to_jsonb(c)||jsonb_build_object('sport', jsonb_agg(to_jsonb(s) - 'category_id'))
from category c
join sport s on s.category_id = c.id
group by c.id;
The above assumes that category.id is defined as the primary key.
It returns one row per category.
If you really want one gigantic array of all rows, you need to aggregate in two steps:
select jsonb_build_object('category', jsonb_agg(to_jsonb(c)||sport))
from category c
join (
select category_id, jsonb_build_object('sport', jsonb_agg(to_jsonb(s) - 'category_id')) as sport
from sport s
group by s.category_id
) s on s.category_id = c.id
Online example

How can I return an ARRAY/JSON structure in a column in postgresql?

Hello I have a set of tables as follows to explain my issue with a minimal example (I want to know how can I retrieve that structure, not change the database structure):
fruit:
id | name | form| texture_id
-------------------------------
1 | Apple | round | 1
2 | Banana | long | 1
fruit_varieties:
id | name | fruit_id | color
-------------------------------
1 | golden | 1| green
2 | fuji | 1| red
3 | canarias | 2| yellow
fruit_texture
id | name
-------------------------------
1 | soft
2 | hard
variety_countries
id | name | fruit_variety_id | average_temperature
-------------------------------
1 | france | 1 | 21
2 | spain | 1 | 24
3 | italy | 2 | 23
I wan to get this structure as follows:
For a given fruit.name=Apple:
{
"fruit_name" = "Apple",
"form" = "round",
"texture" = "soft",
"fruit_properties" = [{
"variety_name" = "Golden",
"color" = "green",
"countries" = [{
"country" = "france",
"avg_temperature" = "21",
}, {
"country" = "spain",
"avg_temperature" = "24",
}
]
}, {
"variety_name" = "fuji",
"color" = "red",
"countries" = [{
"country" = "italy",
"avg_temperature" = "23",
}
]
}
]
}
So I started with something like this
SELECT
fruit.name AS fruit_name,
fruit.form AS form,
fruit_texture.name AS texture,
(
# I don't know how to handle this
) AS fruit_properties
FROM fruit
JOIN fruit_varieties
ON fruit.id = fruit_varieties.fruit_id
WHERE fruit.name = 'Apple'
Now I'm not able to know how can I return that array inside a column, or create a JSON with the whole response. I have been already some hours trying to use some JSON PATH functions I have been suggested in some questions but I am not able to make them work.
Could someone give me a hint using this simple example?
Your output structure is not a standard JSON format. It should be : instead of = between key and value. Considering you want standard JSON output, try below mentioned query:
select row_to_json(d2) from (
select
name,
form,
texture,
json_agg(json_build_object('variety_name',variety_name,'color',color,'countries',countries)) "fruit_properties"
from
(
select
t1.name "name",
t1.form "form",
t3.name "texture",
t2.name "variety_name",
t2.color "color",
json_agg(json_build_object( 'country',t4.name,'temp',t4.average_temperature)) "countries"
from
fruit t1 inner join fruit_varieties t2 on t1.id=t2.fruit_id
inner join fruit_texture t3 on t1.texture_id=t3.id
inner join variety_countries t4 on t4.fruit_variety_id=t2.id
group by 1,2,3,4,5
) d1
group by 1,2,3
) d2
where d2.name='Apple'
DEMO
Above query will return a row with JSON value for each fruit if you will not use where clause.
If you literally want the output as you have mentioned in your question then replace row_to_json(d2) with replace(row_to_json(d2)::text,':', ' = ') in above query.

Implementing Two Level Aggregate in PostgreSQL using Sequelize Function for NodeJS App

Hello guys please bear with me here. I'm using PostgreSQL, Sequelize, Express, and NodeJS to create a backend. I'm wondering if these lines of raw query code can be implemented using Sequelize Model findAll function.
First of all, what I am trying to do here is to calculate the total score of these students. Here are some tables and their relations.
Student Level
| student_id | name | level_id | | level_id | level_name |
|:----------:|:----------:|:--------:| |:--------:|:----------:|
| 1 | John | 1 | > | 1 | Rookie |
| 2 | Jane | 2 | | 2 | Expert |
v
StudentQuiz
| quiz_id | student_id | score |
|:----------:|:----------:|:--------:|
| 1 | 1 | 40 |
| 1 | 1 | 100 |
| 2 | 1 | 80 |
| 1 | 2 | 100 |
| 2 | 2 | 100 |
If I run line of codes below.
SELECT table2.student_id,
s.canvasser_name,
l.level_name,
table2.total_score
FROM (SELECT table1.student_id,
sum(table1.max_score) total_score
FROM (SELECT sq.student_id,
max(sq.score) max_score
FROM public.StudentQuiz sq
GROUP BY sq.quiz_id, sq.student_id) table1
GROUP BY table1.student_id) table2
INNER JOIN public.Student s
ON s.student_id = table2.student_id
INNER JOIN public.Level l
ON l.level_id = s.level_id
ORDER BY table2.total_score DESC
LIMIT 10;
I will get something like this.
| student_id | name | level | total_score |
|:----------:|:----------:|:--------:|:--------------:|
| 1 | John | Rookie | 180 |
| 2 | Jane | Expert | 200 |
Please note that I'm selecting the highest score if more than one quiz with the same id found.
Anyway, I want to implement it using sequelize built in function. What I've been trying to do is something like this.
const result = await StudentQuiz.findAll({
attributes: ['studentId', [sequelize.fn('sum', sequelize.fn('max', sequelize.col('score'))), 'totalPrice'], 'quizId'],
group: 'studentId',
include: [
{
model: Student,
include: [{
model: Level
}],
},
],
offset: 0,
limit: 10
});
The code above throws an error message which is "aggregate function calls cannot be nested".
Any kind of help will be appreciated. Thank you.
P.S. I know i can use sequelize.query() function to use the first code block shown, but that's not the point.
Sequelize is not intended to work with complex aggregations using models. Its primary goal is to provide CRUD operations with models.
To use models in such scenario you can use a model definition to get a schema, a table name and fields to build a query dynamically not knowing exact field names.
I find the solution without using any raw query, though I need to get two tables, that is StudentQuiz and Student that coupled by Level. Here is my answer.
// Finding maximum score and group it based on studentId and quizId
const maxScoreList = await StudentQuiz.findAll({
attributes: ['studentId', 'quizId', [sequelize.fn('max', sequelize.col('score')), 'maxScore']],
group: ['studentId', 'quizId'],
order: ['studentId', 'quizId'],
raw: true
});
// Calculating total score for the same student for each quiz recorded
const scoreArray = [maxScoreList.shift()];
let index = 0;
const unfilteredStudentId = maxScoreList.map((item) => {
if (scoreArray[index].studentId !== item.studentId) {
scoreArray.push(item);
index += 1;
}
scoreArray[index].maxScore += item.maxScore;
return item.studentId;
});
// Filtering studentId that show up more than one time
const extractedStudentId = [...new Set(unfilteredStudentId)];
// Finding student based on studentId inside extractedStudentId array
const student = await Student.findAll({
where: { id: extractedStudentId },
attributes: ['id', 'canvasserId', 'canvasserName', 'canvasserImageUrl'],
include: {
model: Level,
attributes: [['level_name', 'level'], ['icon_url', 'level_image_url']]
},
order: ['id'],
raw: true,
nest: true
});
// Combining total score list to student list
const rankList = student.map((item, idx) => ({ ...item, totalScore: scoreArray[idx] }));
With this much complexity, I agree that using raw query by far the best approach for this case.

Unique values in Sequelize

I use Sequelize ORM for Node.js. I need to get lines with unique values in certain column. Example table:
id | name | group
-----------------
1 | One | 2
2 | Two | 1
3 | Three| 2
4 | Four | 3
5 | Five | 1
Query for column group and result:
id | name | group
-----------------
1 | One | 2
2 | Two | 1
4 | Four | 3
Lines One, Two and Four was the first who had unique group values. How to make it in Sequelize?
A Sequelize raw query is one way of getting out the rows that you want:
/*
var sql =
SELECT r.id,
r.name,
r.groupnum
FROM s04.row r
JOIN
(SELECT min(id) AS id,
groupnum
FROM s04.row
GROUP BY groupnum) s
ON r.id = s.id
*/
return sq.query(sql, { type: sq.QueryTypes.SELECT});
The resulting promise will resolve to a JSON array:
[
{
"id": 1,
"name": "One",
"groupnum": 2
}
...
]
If you then needed to work with these rows as Instances you can call build on each element of the array:
Model.build({ /* attributes-hash */ }, { isNewRecord: false })
See here for an example. If I find a way of doing this via Sequelize function calls (aggregate, find*, etc) that isn't too hideous I'll also post that here as a separate answer.

PostgreSQL Database Model

I have switched to PostgreSQL for my mobile app backend and trying to figure out best way to store and query data. The thing is that storing the data is best as SQL, but retrieving data would be best as document.
So for example, I have table Items:
+----+--------+------+
| id | title | uuid |
+----+--------+------+
| 1 | Hello | 32 |
| 2 | World | 25 |
| 3 | Tom | 435 |
+----+--------+------+
And then table Records:
+----+---------+----------+
| id | itemId | resource |
+----+---------+----------+
| 1 | 1 | res1 |
| 2 | 1 | res2 |
| 3 | 1 | res3 |
| 4 | 2 | res4 |
+----+---------+----------+
Which is pretty much standard SQL approach. Now what I want to get is this:
{
id: 1,
title: "Hello",
uuid: 32,
records: [
{id: 1, resource: "res1"},
{id: 2, resource: "res2"},
{id: 3, resource: "res3"}
]
}
I think you get the picture. I am fairly new to PostgreSQL and I am sure that in all its awesomeness there will be elegant solution to this. All I could think of was creating view table that I could query, but not sure how exactly build the query for this.
If you have a set of tables you are going to query, and you want the output back as a JSON data structure, you now have two choices:
Execute the query, and transform the result to JSON in your application backend. This is a fairly standard approach and is probably still the simplest, especially if the language you are coding your backend in has good JSON support.
Structure the query so that it returns a result encoded in JSON, which you can do thanks to PostgreSQL 9.2 and later.
This article gives a good introduction to the latter approach. Here is a query which gives you what you requested above:
select row_to_json(t)
from (
select items.id,
items.title,
items.uuid,
(
select array_to_json(array_agg(row_to_json(d)))
from (
select records.id,
records.resource
from records
where items.id=records.itemid
) d
) as records
from items
where items.id=1
) as t;
Result:
{
"id": 1,
"title": "Hello",
"uuid": "32",
"records": [
{
"id": 1,
"resource": "res1"
},
{
"id": 2,
"resource": "res2"
},
{
"id": 3,
"resource": "res3"
}
]
}
I used jsonprettyprint.com to make it look nicer - it actually comes out as a single line with no indenting, but still quite valid.
Creating JSON output this way is fiddly, at least for my tastes. I'd probably prefer to do it in the application. But as the JSON support matures I expect it will get easier.