afterUpdate listener in typeorm does not listen to updates on #UpdateDateColumn - postgres DB - node.js

I'm working on a functionality, where in I have an entity called 'Employee' with a few columns like first name, last name, DOB, etc. and two columns:createdAt and updatedAt defined with #CreateDateColumn and #UpdateDateColumn respectively.
My requirement is that, whenever an update operation is performed on this entity, I should be logging the column name that was updated, along with the old and new value that it holds.
I'm performing the update on Employee table using queryRunner.manager.save()
To track the changes,
I'm making use of the entity subscribers 'afterUpdate' event.
Now on performing an update, for e.g. When I change the Name, my Employee entity is correctly updating the name as well as the 'updatedAt' field to current timestamp in DB
However,my 'afterUpdate' listener is only logging the 'name' column with its old and new values.
Its not logging the updatedAt column.
Can anyone please help me understand what's possibly going wrong here?
Entity definition:
...All columns (first name, etc.)
#UpdateDateColumn({name:'updated_at',type:'timestamp',nullable:true})
updatedAt:Date;
Subscriber code:
#EventSubscriber()
export class EmployeeSubscriber implements
EntitySubscriberInterface<EmployeeEntity> {
constructor()
{}
listenTo() {
return EmployeeEntity;
}
afterUpdate(event: UpdateEvent<EmployeeEnitity>){
const {updatedColumns, dataBaseEntity,entity}=event;
updatedColumns.forEach(({propertyName})=>{
//Get the updated column name and old and new values
//col_name = propertyName;
//oldVal= databaseEntity[propertyName as keyof EmployeeEntity] as string,
//newVal= entity?.[propertyName as keyof EmployeeEntity] as string,
})
}
}
I tried using different save operations (via repository, queryRunner, manager), but it didn't work.
Official docs say the event is triggered only on save operation.
If I manually pass the date to updatedAt field, then I am able to get the field within the event handler, but I don't think that's the right approach as manual intervention should not be needed for #UpdateDateColumn

Related

Why is TypeORM convinced that my model is an entity?

Working on nest.js with TypeORM/Postgres.
I've got a calculated_properties column on an entity, like so:
parent.entity.ts
#Entity()
export class Parent {
...
#Column('jsonb')
calculated_properties: CalculatedProperties;
}
calculated_properties.entity.ts
export class CalculatedProperties {
SomeCalc: number,
Other Calc: number,
NestedCalcs: NestedCalc,
With nestedCalc being some other similar types to calculated_properties.entity.ts.
The problem is, when I try to run the app, I get the following error message:
Entity "CalculatedProperties" does not have a primary column. Primary column is required to have in all your entities. Use #PrimaryColumn decorator to add a primary column to your entity.
But I've nowhere said this child type is an entity, and I don't want it to have a PrimaryColumn. In fact, setting an #PrimaryColumn() on it still shows the error - am I missing something obvious here?

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.

Droidparts: how to get to autocreated column names in m2m table?

community.
I am just start to use droidparts.
As I got it is cool library. But it has poor documentation, and no comments in code itself.
I am interested in getting elegant approach to use it.
Well suppose, i've created tables items, users, items2users as many-to-many concept.
Tables items and users are trivial. Table items2users is
#Table(name="items2users")
public class ItemsToUsers extends Entity {
#Column
public Item item;
#Column
public User user;
}
So if I need to get answer if my User has Item I do something like that in UserManager class:
public boolean hasItem(Item item) {
Select<ItemsToUsers> select = select().columns(ID).where({HERE_I_NEED_COLUMN_NAME}, Is.EQUAL, user.id);
}
Droidparts made table with fields 'item_id' and 'user_id'. As I understand HERE_I_NEED_FIELD_NAME must be 'user_id'. As I realize it is automatic naming model for this situation?
Well is there some elegant technique to achive this names or I should construct them manually getting 'user' and '_' and 'id'?
By default the column name will be field name + _id, e.g. item_id & user_id in your case. That can be altered through annotation, e.g. #Column(name="some_other_name").

how to update the field 'updated_at' of a sequelize model without modifiyng any attributes

I'm using sequelize 2.0.0 with PostgreSQL.
I would like to know if it's possible to update the field 'updated_at' of a model with one method. If yes, how can I achieve that?
For instance, in others frameworks, like Laravel, you have model.touch() to automatically update the 'updated_at' of a model.
I've already tried to use model.save() but as the sequelize doc says, calling this method without attributes does nothing. Also, in the doc, I didn't find anything that allow me to do what I need to do simply.
Thanks in advance for help.
Edit:
To give an example of what I'm trying to achieved, I've already had an instance of my model:
Model.findById(1).then(function(myInstance){
[...]
myInstance.update() //here, I didn't change any attributes of myInstance and I would like to update the field udpated_at without doing another query.
[...]
}):
The question is : How can I update the field updated_at of my previous instance with one method?
To update an instance value, you can use instance.set(key, value, [options]).
myInstance.set('updatedAt', new Date());
myInstance.save().then(function() {
// my nice callback stuff
});
The sequelize docs have a good example of doing an update query if you don't have an instance:
Post.update({
updatedAt: null,
}, {
where: {
deletedAt: {
$ne: null
}
}
});
My solution is a little hackey. I had to update a field on the instance to be different than what it was supposed to be, so that sequelize thought that the field changed, even if it didn't; and make sure the proper field data was passed in afterwards.
For example, let's say the variable myInstance has a field named title, and a variable data holds the unchanged (or new) title ( {title:"OLD_OR_NEW_TITLE"} ). If I add to the code myInstance.set('title', data.title+'_FAKE'), then when the update/save method is called ( myInstance.update(data) ), sequelize will think that the field has changed, even though it might not have.

Issue with updating new row by using the mongodb driver

How can I add a new row with the update operation
I am using following code
statuscollection.update({
id: record.id
}, {
id: record.id,
ip: value
}, {
upsert: true
}, function (err, result) {
console.log(err);
if (!err) {
return context.sendJson([], 404);
}
});
While calling this first one i will add the row
id: record.id
Then id:value then i have to add id:ggh
How can i add every new row by calling this function for each document I need to insert
By the structure of your code you are probably missing a few concepts.
You are using update in a case where you probably do not need to.
You seem to be providing an id field when the primary key for MongoDB would be _id. If that is what you mean.
If you are intending to add a new document on every call then you probably should be using insert. Your use of update with upsert has an intended usage of matching a document with the query criteria, if the document exists update the fields as specified, if not then insert a new document with the fields specified.
Unless that actually is your goal then insert is most certainly what you need. In that case you are likely to rely on the value of _id being populated automatically or by supplying your own unique value yourself. Unless you specifically want another field as an identifier that is not unique then you will likely want to be using the _id field as described before.

Resources