Check for duplicates before inserting into table - node.js

I'm writing a nodejs application which users can buy products . I have a mysql database and sequelize. I have an object like this:
const Data = {
TransID,
TransTime,
Amount: TransAmount,
BillRefNumber,
MSISDN,
FirstName,
MiddleName,
LastName,
ShortCode: BusinessShortCode,
};
For any new transactions, I would like to check, using the TransId, whether this transaction exists in my table using the TransId . What is the best way to achieve this?

Maybe one of the best ways is to add a unique attribute to the TransID field in the database table. When you insert it, add a try-catch. It will catch an error if the same TransID already exists in the database. All you have to do is display the error.

Related

How to INSERT with SELECT values in TypeORM

Lets say I have main table Users and a reference table UserRoles such that each User has one Role saved in the column roleId, and every role has an id and a description.
If I want to insert a new User with the role Administrator, the following SQL query would work:
INSERT INTO `users` (`name`, `roleId`)
VALUES ('John Doe', (SELECT `id` FROM `roles` WHERE `roles`.`description` = 'admin'));
How would I replicate the same in TypeORM having two entities User and Role?
I know I can do the following:
const adminRole = await Role.findOne({description: 'admin'});
const newUser = User.create({name: 'John Doe'});
newUser.role = adminRole;
await newUser.save();
But this would rather be equivalent to SELECT the role into a variable and then using that variable during the INSERT. is there a way to condense this into one query so that the database is hit only once?
I know that I can create an user with the relation like this
User.create({name: 'John Doe', role: {id: 1}});
But I need to know the id for this. If I put the name like the following
User.create({name: 'John Doe', role: {name: 'admin'}});
I get the following error Error: Cannot find alias for relation at type because I have not loaded the relation.
I've found information on how to make an INSERT INTO SELECT statement here, but this is where the whole insert comes from a select, not just a particular column.
Is there a way to emulate this query for insertions? or I'm forced to either do it in two steps (or as many as reference columns as I have) or use the query builder?
Thanks you in advance

Proper Sequelize flow to avoid duplicate rows?

I am using Sequelize in my node js server. I am ending up with validation errors because my code tries to write the record twice instead of creating it once and then updating it since it's already in DB (Postgresql).
This is the flow I use when the request runs:
const latitude = req.body.latitude;
var metrics = await models.user_car_metrics.findOne({ where: { user_id: userId, car_id: carId } })
if (metrics) {
metrics.latitude = latitude;
.....
} else {
metrics = models.user_car_metrics.build({
user_id: userId,
car_id: carId,
latitude: latitude
....
});
}
var savedMetrics = await metrics();
return res.status(201).json(savedMetrics);
At times, if the client calls the endpoint very fast twice or more the endpoint above tries to save two new rows in user_car_metrics, with the same user_id and car_id, both FK on tables user and car.
I have a constraint:
ALTER TABLE user_car_metrics DROP CONSTRAINT IF EXISTS user_id_car_id_unique, ADD CONSTRAINT user_id_car_id_unique UNIQUE (car_id, user_id);
Point is, there can only be one entry for a given user_id and car_id pair.
Because of that, I started seeing validation issues and after looking into it and adding logs I realize the code above adds duplicates in the table (without the constraint). If the constraint is there, I get validation errors when the code above tries to insert the duplicate record.
Question is, how do I avoid this problem? How do I structure the code so that it won't try to create duplicate records. Is there a way to serialize this?
If you have a unique constraint then you can use upsert to either insert or update the record depending on whether you have a record with the same primary key value or column values that are in the unique constraint.
await models.user_car_metrics.upsert({
user_id: userId,
car_id: carId,
latitude: latitude
....
})
See upsert
PostgreSQL - Implemented with ON CONFLICT DO UPDATE. If update data contains PK field, then PK is selected as the default conflict key. Otherwise, first unique constraint/index will be selected, which can satisfy conflict key requirements.

Typeorm querybuilder update get updated result

I'm running a query-builder that updates multiple users based on last logged in date, meaning I don't know which users are getting updated. Here is my code, which does not provide information about which users it updated.
await getConnection()
.createQueryBuilder()
.update(User)
.set({
isDeactivated: true
})
.where('lastConnected < :someTimeAgo', { someTimeAgo })
.andWhere('isDeactivated = :isDeactivated', { isDeactivated: false })
.execute()
.then(result => {
// Result: UpdateResult { generatedMaps: [], raw: undefined }
})
How can I access the updated data? Database is SQL Server.
Normally you cannot find which rows were updated by an UPDATE statement in SQL, hence tyeorm cannot tell you.
Here are several solutions if you REALLY need to know which rows were updated.
Before go ahead, ask WHY do you need to know? Do you REALLY need to know?
If, after careful consideration, you find you need to know which rows were updated, there are several solutions:
In your code, find the users to be deleted, then delete them one at a time, logging info on each one as you go.
Create a table in the database containing the user id's to be deactivated. Populate this table first: INSERT INTO deactivatedusers (userid) SELECT userid FROM users WHERE ... then run UPDATE users SET isDeactivated = 1 WHERE userid IN SELECT userid FROM deactivatedusers then to find which users were deactivated: SELECT userid FROM deactivatedusers and finally clear deactivatedusers ready for next time, either with DELETE FROM deactivatedusers or TRUNCATE TABLE deactivatedusers
Since you are using MS SQL Server, this provides OUTPUT INTO specifically to do what you are asking (non standard SQL, so only works with this DBMS). If you decide to use this approach, you should write a stored procedure to do the update and return the updated data back to caller, then call this stored proc from typeorm.

Sequelize upsert with conditions on previous data

I have a server that accepts RESTful-style requests. For PUT of a certain class of objects, I want to either insert a new record with the request body data, or update a previous record. For that, I'm using Sequelize upsert.
app.put('/someModel/:id', (req, res, next) => {
const data = JSON.parse(JSON.stringify(req.body));
data.id = req.params.id;
models.SomeModel.upsert(data).then(() => {
return models.SomeModel.findByPk(req.params.id);
}).then(res.send.bind(res)).catch(next);
});
On update, I only want to update the database record if it hasn't previously been changed. That is, if a Client A fetches a record, Client B then modifies that record, and then Client A subsequently tries to update it, the request should fail since the record was updated by Client B in between Client A's fetch and update. (On the HTTP side, I'm using the If-Unmodified-Since request header.)
Basically, I need a way to:
UPDATE table
SET
field1="value1",
field2="value2"
WHERE
id=1234 AND
updatedAt="2019-04-16 17:41:10";
That way, if the record has been updated previously, this query won't modify data.
How can I use Sequelize upsert to generate SQL like this?
At least for MySql, that wouldn't be valid - upsert results in
insert into table (field1) values ('value1') on duplicate key update field1 = values(value1);
The syntax doesn't allow for a WHERE clause. Another DBMS, maybe?
With raw sql, you could fake it with the IF function:
INSERT INTO table (field1) VALUES ('value1') ON DUPLICATE KEY UPDATE
field1 = IF(updatedAt = "2019-04-16 17:41:10", values(field1), field1);
but it's kind of ugly.

Sails.js: Dynamic table name on models

I have made a JS logger application in Sails.js and everything looks great.
Now, I'm on my way to scale the application: I need to use several tables for the same model (e.g. a table for session1 sesson2 etc based on id).
Let's say that for model "Pageview", I'll be using different tables, like "Pageview1", "Pageview2", and so on.
How could I define dynamically the tableName of that model, so I can change it on every request according to a param or attribute.
So far, I have tried this way
var tableId = 2;
Pageview.tableName = "pageview" + tableId;
Pageview.create(values, function...);
That code does not break the application, or throw any errors, but the record was saved on the default table, instead of the one I wanted.
I dont think it is possible to do so , but when i read this
I think you can use the custom format to dynamically define table names.
If you are inserting a row into a table with an auto increment primary key, you can retrieve the insert id like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function(err, result) {
if (err) throw err;
console.log(result.insertId);
});
if this is valid for rows , then it might be valid for tables.

Resources