Transforming mongoDb json file into SQL tables - sql

I have a mongo DB Json file that I in some way want to squeeze into a SQL database and have it make sense but I don't know what that would look like. The file looks like this:
"_id":{
"$oid":"61377659d24fd78398a5a54a"
},
"currentTotalValue":0,
"stocks":[
{
"ticker":"TSLA",
"baseCurrency":"USD",
"numberOfShares":20
},
{
"ticker":"GME",
"baseCurrency":"USD",
"numberOfShares":100
},
{
"ticker":"KINV-B",
"baseCurrency":"SEK",
"numberOfShares":50
},
{
"ticker":"BBD.B",
"baseCurrency":"CAD",
"numberOfShares":100
},
{
"ticker":"NAS",
"baseCurrency":"NOK",
"numberOfShares":20000
}
]
}
{
"_id":{
"$oid":"61377666d24fd78398a5a558"
},
"currentTotalValue":0,
"stocks":[
{
"ticker":"TSLA",
"baseCurrency":"USD",
"numberOfShares":1
},
{
"ticker":"GME",
"baseCurrency":"USD",
"numberOfShares":3457
},
{
"ticker":"KINV-B",
"baseCurrency":"SEK",
"numberOfShares":3547
},
{
"ticker":"BBD.B",
"baseCurrency":"CAD",
"numberOfShares":5768
},
{
"ticker":"NAS",
"baseCurrency":"NOK",
"numberOfShares":100000
}
]
}
So in SQL is this two separate tables with one portfolio in each or?
And if so what would those tables look like?

It depends on how one interprets the file. One could say, there are two portfolios which are described by some oid and a currentTotalValue two which the stocks belong to.
CREATE TABLE portfolios (
oid VARCHAR(24) NOT NULL PRIMARY KEY,
currentTotalValue INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE stocks (
id INTEGER NOT NULL PRIMARY KEY,
portfolio_id VARCHAR(24) NOT NULL,
ticker VARCHAR(20) NOT NULL,
baseCurrency VARCHAR(3) NOT NULL,
numberOfShares INTEGER NOT NULL,
CONSTRAINT fk_stocks_portfolios
FOREIGN KEY(portfolio_id) REFERENCES portfolios(oid)
);
If you don't need the portfolio you can drop it and remove the foreign key constraint from table stocks:
CREATE TABLE stocks (
id INTEGER NOT NULL PRIMARY KEY,
portfolio_id VARCHAR(24) NOT NULL,
ticker VARCHAR(20) NOT NULL,
baseCurrency VARCHAR(3) NOT NULL,
numberOfShares INTEGER NOT NULL
);
Warning: this is just a rough sketch to get a basic idea. Depending on the used DBMS you could use an auto increment value for the stocks id.

Related

Typescript Sequelize create data with keys linked to data in a transaction

I'm strugling with something that maybe is pretty simple.
I'm using a postgrès SQL with sequelize and typescript.
what I'm trying to do is to create two things and one as Reference on the other but if the creation of one fail then I don't want to commit anythigs.
This is my code where I'm trying to create someone and assign hime some shoes.
CREATE TABLE User
(
id BIGSERIAL PRIMARY KEY,
firstname TEXT,
lastName TEXT
);
CREATE TABLE Shoes
(
id BIGSERIAL PRIMARY KEY,
size INTEGER NOT NULL,
idUser BIGINT REFERENCES User(id) NOT NULL
);
async function operations() {
const t = await sequelize.transaction();
try {
await User.create({
firstName: 'Bart',
lastName: 'Simpson'
}, { transaction: t });
await Shoes.create({
idUser: // here I want the id of my futur new creation (bart simpson)
size: 43
}, { transaction: t });
await t.commit();
} catch (error) {
await t.rollback();
}
}
operations.then(() => {/*do something*/})
the thing is, I don't know how to get the futur Id of my new user and if I'm putting something hard like 1 if the database is empty or if I get the latest id user and I'm adding 1 then I get an error violates foreign key constraint.
I think it's because the user isn't existing in the database but it exist in the transaction.
If someone could help me :)
I fact sending a transaction in a get can also return the value that will be created in the transaction so just need to use get and send the exact same transaction inside the methode

How I can update one to many relation in Postgres?

Here is my first table question.
CREATE TABLE "question" (
"question_id" serial NOT NULL,
"question" TEXT NOT NULL UNIQUE,
"added_at" TIMESTAMP NOT NULL,
"question_marks" integer NOT NULL,
CONSTRAINT "question_pk" PRIMARY KEY ("question_id"))
Questions have many options, so I referring every option row with question_id
CREATE TABLE "option" (
"option_id" serial NOT NULL,
"option" TEXT NOT NULL,
"option_question_id" integer NOT NULL,
"option_correct" BOOLEAN NOT NULL,
CONSTRAINT "option_pk" PRIMARY KEY ("option_id"))
ALTER TABLE "option" ADD CONSTRAINT "option_fk1" FOREIGN KEY ("option_question_id") REFERENCES "question"("question_id") ON DELETE CASCADE;
Now, How can I update both tables in one query?
I building an API. The below-given output is for request. The request will response with question details and options for the question.
I am able to update question but questions have many options, How can I update options?
"questionDetails": [
{
"question_id": 30,
"question": "What is gravity of Saturn?",
"added_at": "2020-02-20T18:30:00.000Z",
"question_marks": 1
}
],
"options": [
{
"option_id": 19,
"option": "20",
"option_question_id": 30,
"option_correct": true
},
{
"option_id": 20,
"option": "30",
"option_question_id": 30,
"option_correct": false
},
{
"option_id": 21,
"option": "40",
"option_question_id": 30,
"option_correct": false
},
{
"option_id": 18,
"option": "400000000",
"option_question_id": 30,
"option_correct": false
}
]
}
Now Can I update this relation?
You can chain multiple operations together in a single query by using CTEs that have returning clauses.
with
__parent as(
update
my_schema.parent_table
set
col_1 = 'a',
col_2 = 'b'
where
id_col = 3
returning
id_col
)
update
my_schema.child_table
set
col_1 = 'c'
where
parent_id = (select id_col from __parent)
The same thing can be done for insert and delete statements.
Do note you actually need to select from the CTE in the following query, otherwise the statement within will not be executed.

How to INSERT INTO table(column) VALUES(value) WHERE column2 = value

I am working on a Time Clock program but I am having trouble with this query:
INSERT INTO users(time_in) VALUES($2) WHERE username = $1
Table:
CREATE TABLE users (
id SERIAL PRIMARY KEY NOT NULL,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
time_json VARCHAR,
time_in VARCHAR
);
Here is the error that I am getting:
error: syntax error at or near "time_in"
at Connection.parseE (\...\node_modules\pg\lib\connection.js:606:11)
at Connection.parseMessage (\...\node_modules\pg\lib\connection.js:403:19)
at TLSSocket.<anonymous> (\...\node_modules\pg\lib\connection.js:123:22)
at TLSSocket.emit (events.js:210:5)
at addChunk (_stream_readable.js:308:12)
at readableAddChunk (_stream_readable.js:289:11)
at TLSSocket.Readable.push (_stream_readable.js:223:10)
at TLSWrap.onStreamRead (internal/stream_base_commons.js:182:23) {
name: 'error',
length: 95,
severity: 'ERROR',
code: '42601',
detail: undefined,
hint: undefined,
position: '8',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'scan.l',
line: '1134',
routine: 'scanner_yyerror'}
Code for the function I am working on:
function postTimeIn(user, callback) {
const timeIn = getTime();
params = [user, timeIn];
const sql = 'INSERT INTO users(time_in) VALUES($2) WHERE username = $1';
pool.query(sql, params, function (err, result) { ...
The WHERE clause would make sense with an UPDATE:
UPDATE users
SET time_in = $2
WHERE username = $1;
Is that what you really want?
username should be defined UNIQUE for this - and probably in any case.
time_json should probably be type json or jsonb. time_in should probably be timestamptz.
An INSERT would not make any sense (apart from the invalid syntax), as you would have to fill in all NOT NULL columns without column default at the same time:
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
The problem is that you are trying to insert a record with a where condition. You can only use a where condition only as a filter when you are inserting values selected from another table
like.
INSERT INTO table(column1,column2,...)
SELECT column1,column2,...
FROM another_table
WHERE condition;
In your instant you should do an update as suggested above because you are changing the attribute value of an already existing record.

Select sql query to group by nested json

The data I am getting from select query is something like this
[{
id: 'CB2FD8B7-7E6D-4BF3-8E73-70D41FFBE456',
products: '[{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6B7"}]',
falconpay_api_response: null,
dhl_updated_by: null
}, ... ]
What I am doing is fetching orders and then parsing products attribute and extracting product_id and counting the number of time the product_id occured in the number of different json objects.
This would be very time consuming if number of rows to fetch are in thousands and then extracting ids and counting its occurrences.
Is there any effective way to use GROUP by and get directly occurrences of product_id for thousands of rows.
You can use it!
var data = [{
id: 'CB2FD8B7-7E6D-4BF3-8E73-70D41FFBE451',
products: [{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6B7"}],
falconpay_api_response: null,
dhl_updated_by: null
},{
id: 'CB2FD8B7-7E6D-4BF3-8E73-70D41FFBE452',
products: [{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6B7"},{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6K7"}],
falconpay_api_response: null,
dhl_updated_by: null
},{
id: 'CB2FD8B7-7E6D-4BF3-8E73-70D41FFBE453',
products: [{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6K7"}],
falconpay_api_response: null,
dhl_updated_by: null
},{
id: 'CB2FD8B7-7E6D-4BF3-8E73-70D41FFBE454',
products: [{"product_id":"22061DA1-5D64-475A-B36A-140ECFE8D6B7"}],
falconpay_api_response: null,
dhl_updated_by: null
}];
var a =[];
data.forEach(function(order){
order.products.forEach(function(product){
if(a[product.product_id] == undefined){
a[product.product_id] = [];
}
a[product.product_id].push(order);
})
});
console.log(a);
Try the following Query (That's only works in JSON data type) :-
SELECT products->>'$.product_id' products,
count(products)
FROM events
GROUP BY products->>'$.product_id';
And Following Link will helpful to you :-
[http://www.mysqltutorial.org/mysql-json/]

Timestamptz, same point in time but different representation for same query with 'set local time zone'

I am trying to build my web app that will store the data on a PostgreSQL database server running on some location on Earth and will have users connecting from other locations, so probably different timezones and offsets than my servers.
I need to show the dates and times of the actions like, posts created, posts edited, comments submitted, etc. according to the each connecting user. This is just like the StackExchange. However I am running into problems of timezones and offsets as described as follows:
Everything seems working correct in my pgAdmin3 SQL Editor. When I write the query below in pgAdmin3 SQL Editor with set local time zone 'Europe/Oslo', for example, I get both the posts and tags table created_at fields correct with +2 offset in the output. In the output row, the created_at field of posts table is 2016-08-29 19:15:53.758+02 and for same row created_at for tags table is 2016-08-29T19:15:53.758+02:00.
However, when I put it in a route function in my Nodejs Express.js server with pg-promise as the connection lib, I only get the tags table created_at field correct with the time in Oslo with timezone offset appended as expected, I get created_at field of the posts table in UTC not as expected.
All timestamps are defined as timestamp(3) with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP as shown below. Also, without the setting set local time zone, I get the same behaviour, for first table I get UTC time, for the latter I get timestamp with offset of server appended.
Does not the set local time zone directive bind all the query? What is the missing point in my approach?
an example query I use:
select
q.*, -- created_at timestamp (with time zone) is one of those columns
u.name as author,
u.reputation,
case when count(t.*)=0 then '[]' e json_agg(t.*) end as tags
from posts q
-- authors
join users u
on q.author_id = u.id
-- tags
left join post_has_tag p_h_t
on q.id = p_h_t.post_id
left join tags t
on p_h_t.tag_id = t.id
where q.post_type = 'question'
group by q.id, u.id;
An example express.js route function:
trialRoutes.get('/x', function (req, res) {
db.query(
`
--begin;
SET LOCAL TIME ZONE 'Europe/Oslo';
SELECT
q.*, -- created_at timestamp (with time zone) is already in here
u.name AS author,
u.reputation,
CASE WHEN count(t.*)=0 THEN '[]' ELSE json_agg(t.*) END as tags
FROM posts q
-- authors
JOIN users u
ON q.author_id = u.id
-- tags
left join post_has_tag p_h_t
on q.id = p_h_t.post_id
left join tags t
on p_h_t.tag_id = t.id
WHERE q.post_type = 'question'
group by q.id, u.id;
--commit;
`
)
.then(function (data) {
res.json(data)
})
.catch(function (error) {
console.log("/login, database quesry error.", error);
});
})
The result I get from Express.js http server with pg-promise. Note the different timestamps that actually should point same point in UTC, which is correctly done, and representation which is not correctly done:
[
{
"id": "7",
"created_at": "2016-08-29T21:02:04.153Z", // same point in time, different representation
"title": "AAAAAAAAAAA",
"text": "aaaaa aaaaaaa aaaaaa",
"post_url": "AAAAAAAAAAA",
"score": 0,
"author_id": 1,
"parent_post_id": null,
"post_type": "question",
"is_accepted": false,
"acceptor_id": null,
"timezone": "2016-08-29T20:02:04.153Z",
"author": "Faruk",
"reputation": 0,
"tags": [
{
"id": 4,
"created_at": "2016-08-29T23:02:04.153+02:00", // same point in time, different representation
"label": "physics",
"description": null,
"category": null
}
]
},
{
"id": "6",
"created_at": "2016-08-29T17:24:10.151Z",
"title": "Ignoring timezones altogether in Rails and PostgreSQL",
"text": "Ignoring timezones altogether in Rails and PostgreSQL",
"post_url": "Ignoring-timezones-altogether-in-Rails-and-PostgreSQL",
"score": 0,
"author_id": 2,
"parent_post_id": null,
"post_type": "question",
"is_accepted": false,
"acceptor_id": null,
"timezone": "2016-08-29T16:24:10.151Z",
"author": "Selçuk",
"reputation": 0,
"tags": [
{
"id": 3,
"created_at": "2016-08-29T19:24:10.151+02:00",
"label": "sql",
"description": null,
"category": null
}
]
}
]
The definition of the posts and tags tables used here:
-- questions and answers
CREATE TABLE posts
(
id bigserial PRIMARY KEY,
created_at timestamp(3) with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
title character varying(100),
text text,
post_url character varying(100),
score integer DEFAULT 0,
author_id integer NOT NULL REFERENCES users (id),
parent_post_id integer REFERENCES posts (id),
post_type varchar(30),
is_accepted boolean DEFAULT FALSE,
acceptor_id integer REFERENCES users (id) DEFAULT NULL
--seen_by_parent_post_author boolean DEFAULT false
--view_count
--accepted_answer_id
--answer_count
);
CREATE TABLE tags
(
id bigserial PRIMARY KEY,
created_at timestamp(3) with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
label character varying(30) NOT NULL,
description character varying(200),
category character varying(50)
);