Prisma: Finding items where two fields have the same value - prisma

I would like to find items in a Prisma db where the values for two columns are the same. The use case is to compare the 'created_at' and 'updated_at' fields to find items that have never been updated after their initial creation. In raw SQL I would do something like:
select updated_at,
cast(sign(sum(case when updated_at = created_at then
1
else
0
end)) as int) as never_modified
from tab
group by updated_at
Is it possible to achieve this in Prisma?

You would need to use Raw Queries to compare time values from the same table.
Here's an example of how you could achieve this, assuming a PostgreSQL database for the following query.
import { PrismaClient } from '#prisma/client'
const prisma = new PrismaClient()
async function initiateDatesComparisonRawQuery() {
const response =
await prisma.$queryRaw`SELECT * FROM "public"."Project" WHERE "created_at" = "updated_at";`;
console.log(response);
}
await initiateDatesComparisonRawQuery();

you can use the preview feature fieldReference of prisma.
schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["fieldReference"]
}
your code
prisma.project.findMany({
where: { created_at: prisma.project.fields.updated_at }
})

Related

data encountered at first instance of date is returned in sequelize

I wrote a query to get the data from the table where the data of today's date is to be fetched, if data for today's date isn't present, then the latest data from latest date in the past is fetched.
var db_data = await db.daily_tip({
where: { date_for_show: { [Op.lte]: payload_date }
})
where, if data encountered at the first instance which is less than the current date is fetched.
How do I modify this query to return the data as of this query
SELECT id,tip,date_for_show from daily_tip WHERE date_for_show <= '${payload_date}' ORDER BY date_for_show DESC LIMIT 1`
Just use order and limit options like this:
var db_data = await db.daily_tip({
where: { date_for_show: { [Op.lte]: payload_date },
order: [['date_for_show', 'DESC']],
limit: 1
})

How to order by field called "count" in Prisma?

I'm having hard times to find out how to order by count field in Prisma.
The query looks like this:
const where = // ...
const limit = // ...
const skip = // ...
const data = await this.prisma.translation.findMany({
where,
take: limit,
skip: offset,
orderBy: {
count: 'asc'
// ^ here is the issue, because count seems to be reserved for aggregations
}
});
Prisma model:
model Translation {
id String
count Int #default(0)
}
I found the docs here https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#orderby but it does not say anything how to say to prisma that the count does not mean aggregation but a column name.
The error I'm getting:
Invalid `prisma.translation.findMany()` invocation:\n\n\n Failed to validate the query: `Assertion error: Attempted conversion of non-map ParsedInputValue (Single(String(\"asc\"))) into map failed..` at ``
PS. I found this issue on GitHub that is still open https://github.com/prisma/prisma/issues/7806, gonna ask also there for some workaround or something...
Thanks for any help :-)
This has been fixed in Prisma Version 3.0.1.
If you need to solve this in Prisma v2, you could change the field name in prisma and use the #map annotation to point to the count column in your database table.
Example Prisma schema
model Translation {
id Int #id #default(autoincrement())
transactionCount Int #default(0) #map(name: "count")
}
Inside your prisma code you would use transactionCount instead of count. But there won't be any change to the underlying database, which will still have the column named count.
For more info, take a look at the Prisma docs for using custom field names.

How to update with returning values in TypeORM?

I wanted to update values and to return specified columns with PostgreSQL.
So far, what I found was update the value then use findOne, but then again it will always use two queries to achieve what I want.
Another is using RAW SQL, UPDATE ... SET ... WHERE ... RETURNING * and this seems a great solution so is there a way to achieve this with TypeORM using UpdateQueryBuilder?
You can use createQueryBuilder:
const firstUser = await connection
.getRepository(User)
.createQueryBuilder("user")
.update<User>(User, {firstName: 'new first name'})
.where("user.id = :id", { id: 1 })
.returning(['id', 'email'])
.updateEntity(true)
.execute();
Notice: there are many ways in type orm to use createQueryBuilder such as: BaseEntity, Repository, EntityManager.
If using repository, this is slightly modified answer and inspired from Noam's answer:
import {
EntityRepository,
Repository,
} from "typeorm";
import { User } from "../entities/user";
#EntityRepository(User)
export class UserRepository extends Repository<User> {
// ... other functions
updateUser = async (payload: User, id: string): Promise<User> => {
const updatedData = await this.createQueryBuilder("user")
.update<User>(User, { ...payload })
.where("user.id = :id", { id: id })
.returning("*") // returns all the column values
.updateEntity(true)
.execute();
return updatedData.raw[0];
};
}

Sequelize bulk update with inner join

I am currently working with Sequelize and can not figure out how to update bulk when im associating two tables together. I have the follow:
Tables:
members
user_id
channel_id
all
activities
user_id
channel_id
I am trying to update members.all when the user_ids match, members.channel_id is 2 and activities.channel_id is not 2.
Here is working Postgresql:
UPDATE members AS m
SET "all" = true
FROM activities AS a
WHERE m.user_id = a.user_id
AND m.channel_id = 2
AND a.current_channel != 2;
Is this possible to do is sequelize? How do include a.current_channel != 2 into my current update?
Member.update(
{ all: true },
{ where: { channel_id: channelId } },
)
When I try to add an include it does not work.
I think you can't do something like that using Sequelize update method. I would use the include option in a findAll method, but as far as I can see on the documentation, there is no include option for the update method.
You could use a raw query to use directly the query.
sequelize.query("UPDATE members AS m SET "all" = true FROM activities AS a WHERE m.user_id = a.user_id AND m.channel_id = 2 AND a.current_channel != 2").spread((results, metadata) => {
// Results will be an empty array and metadata will contain the number of affected rows.
});
Generally, i use this hack
models.findAll({
where: {
// which models to update
}
}).then(targets => {
models.target.update({
// your updates
},{
where : {
target_primary_key: targets.map(t => t.primary_key)
}
})
})

How to return and update a table in bookshelf knex

I am using postgresql, knex, and bookshelf to make queries to update my users table. I would like to find all users who didn't sign in during a specific time and then update their numAbsences and numTardies field.
However it appears that when running a raw sql query using bookshelf.knex the result that I get for users is an array of objects rather than an array of bookshelf objects of objects because I can't save the objects directly to the database when I try to use .save(). I get the exception user.save is not a function.
Does anyone know how I can update the values in the database for the users? I've seen the update function but I need to also return the users in absentUsers so I select them currently.
// field indicates whether the student was late or absent
var absentUsers = function(field){
// returns all users who did not sign in during a specific time
if (ongoingClasses){
return bookshelf.knex('users')
.join('signed_in', 'signed_in.studentId', '=', 'users.id')
.where('signed_in.signedIn', false)
.select()
.then(function(users){
markAbsent(users, field);
return users;
});
}
}
var markAbsent = function(users, field){
users.forEach(function(user){
user[field]++;
user.save();
})
}
I've solved my problem by using another sql query in knex. It seemed there was no way to use a sql query and then use standard bookshelf knex methods since the objects returned were not bookshelf wrapper objects.
var absentUsers = function(field){
// returns all users who did not sign in during a specific time
if (ongoingClasses){
return bookshelf.knex('users')
.join('signed_in', 'signed_in.studentId', '=', 'users.id')
.where('signed_in.signedIn', false)
.select()
.then(function(users){
markAbsent(users, field);
});
}
}
var markAbsent = function(users, field){
users.forEach(function(user){
var updatedUser = {};
updatedUser[field] = user[field]+1;
bookshelf.knex('users')
.where('users.id', user.id)
.update(updatedUser).then(function(){
});
});
}
With your code bookshelf.knex('users') you leave the "Bookshelf world" and are in "raw knex world". Knex alone doesn't know about your Bookshelf wrapper objects.
You may use Bookshelf query method to get the best of both worlds.
Assuming your model class is User, your example would look approximately like
User.query(function(qb) {
qb.join('signed_in', 'signed_in.studentId', 'users.id')
.where('signed_in.signedIn', false);
})
.fetchAll()
.then(function(bookshelfUserObjects) {
/*mark absent*/
return bookshelfUserObjects.invokeThen('save'); // <1>
});
<1> invokeThen: Call model method on each instance in collection