count with where query to code by use sequelize - sql

i want change this query to code by use sequelize and node.js depend on where
select COUNT(gender) as genderCount from customers where gender = "male"
but i don't know how to add where
this original code:
Customer.findAll({
attributes: {
include: [[Sequelize.fn("COUNT", Sequelize.col("gender")), "genderCount"]] }
}).then(data => {
res.send(data)
})

For "sequelize": "^5.21.3":
Option 1.
const customers = await Customer.findAll({
attributes: [[Sequelize.fn('COUNT', Sequelize.col('gender')), 'genderCount']],
where: {
gender: 'male',
},
raw: true,
});
The execution result:
Executing (default): SELECT COUNT("gender") AS "genderCount" FROM "customers" AS "Customer" WHERE "Customer"."gender" = 'male';
[ { genderCount: '3' } ]
Option 2. You can use Model.count().
Count the number of records matching the provided where clause.
const customers = await Customer.count({ col: 'gender', where: { gender: 'male' } });
The execution result:
Executing (default): SELECT count("gender") AS "count" FROM "customers" AS "Customer" WHERE "Customer"."gender" = 'male';
The above examples base on data records in the database:

i solve it from query:
select COUNT(gender) as genderCount from customers where gender = "male"
to code sequelize :
await Customer.findAll({
attributes: {
include: [[Sequelize.fn("COUNT", Sequelize.col('gender')), "genderCount"]] ,
},
where:[{"gender":'male'}]
}).then(data => {
res.send(data)
})

Related

Strapi GROUP BY and COUNT fields with the same value

Is there any way in strapi to group by entries with the same fields and count its total?
Trying to create a Poll App which has "Response" Collection containing an "Answer" Field (enum: a, b, c, d). Would like to group responses with the same answers. Something like this:
{
"answer": "a",
"total": 3
}, {
"answer": "b",
"total": 1
}
Is it possible out of the box?
To give more context, here's its sql counterpart:
select *, count(answers) from responses group by answers
there is no known default way for groupby with entity service, however there is count query:
/src/answer/controllers/answer.js
const { createCoreController } = require("#strapi/strapi").factories;
module.exports = createCoreController("api::answer.answer", ({ strapi }) => ({
async find(ctx) {
let { query } = ctx;
let answers = await strapi.db.query("api::answer.answer").findMany({
...query,
});
answers = await Promise.all(answers.map(async (answer) => ({
...answer,
total: await strapi.db.query("api::answer.answer").count({where: '...'})
})))
return answers
},
}));
or you can use raw query like this:
let { rows } = await strapi.db.connection.raw(
`select id from posts where published_at IS NOT null order by random() limit ${count};
`);
or
let { rows } = await strapi.db.connection.raw(
`select *, count(answers) from responses group by answers;`);

TypeORM The results of the conditional query were not match

I set the where condition in the find statement, but the results of the conditional query where not match.
The find query:
async getRegister() {
const result = await this.registerModel.findOne({
where: {
session: 1,
user: 2,
},
select: ['id', 'created_time'],
});
return result;
}
The register entity:
#Entity('register')
export class Register {
#PrimaryGeneratedColumn()
id: number;
#Column({
type: 'text',
nullable: true,
unique: true,
})
no: string;
……
#ManyToOne(type => User, user => user.registers)
user: User;
#OneToOne(type => Session)
#JoinColumn()
session: Session;
}
The formatted SQL statement:
query: SELECT DISTINCT "distinctAlias"."Register_id" AS "ids_Register_id" FROM (SELECT "Register"."id" AS "Register_id", "Register"."created_time" AS "Register_created_time" FROM "register" "Register" INNER JOIN "session" "Register__Register_session" ON "Register__Register_session"."id"="Register"."sessionId" AND ("Register__Register_session"."deleted_time" IS NULL) INNER JOIN "user" "Register__Register_user" ON "Register__Register_user"."id"="Register"."userId" AND ("Register__Register_user"."deleted_time" IS NULL) WHERE "Register"."deleted_time" IS NULL) "distinctAlias" ORDER BY "Register_id" ASC LIMIT 1
query: SELECT "Register"."id" AS "Register_id", "Register"."created_time" AS "Register_created_time" FROM "register" "Register" INNER JOIN "session" "Register__Register_session" ON "Register__Register_session"."id"="Register"."sessionId" AND ("Register__Register_session"."deleted_time" IS NULL) INNER JOIN "user" "Register__Register_user" ON "Register__Register_user"."id"="Register"."userId" AND ("Register__Register_user"."deleted_time" IS NULL) WHERE ( "Register"."deleted_time" IS NULL ) AND ( "Register"."id" IN (7) )
I could not find the parameter set
where: {
session: 1,
user: 2,
},
When I use sql, I get the right results.
await this.registerModel.query(
`select id, created_time from register where userId = ${userId} and sessionId = ${sessionId}`
);
I have fixed this issuse.
First modified the registered entity
#Entity('register')
export class Register {
#PrimaryGeneratedColumn()
id: number;
#Column({
type: 'text',
nullable: true,
unique: true,
comment: '准考证号',
})
no: string;
……
#ManyToOne(type => User, user => user.id)
user: User;
#ManyToOne(type => Session, session => session.id)
session: Session;
}
Last modified the find query:
const result = await this.registerModel.findOne({
where: {
user: {
id: userId,
},
session: {
id: sessionId,
},
},
select: ['id', 'created_time'],
});
return result;

How to show generated SQL / raw SQL in TypeORM queryBuilder

I developed typeorm querybuilder. For the purpose of debugging, I'd like to show the generated SQL query.
I tested printSql() method, but it didn't show any SQL query.
const Result = await this.attendanceRepository
.createQueryBuilder("attendance")
.innerJoin("attendance.child", "child")
.select(["attendance.childId","child.class","CONCAT(child.firstName, child.lastName)"])
.where("attendance.id= :id", { id: id })
.printSql()
.getOne()
console.log(Result);
It returned the following:
Attendance { childId: 4, child: Child { class: 'S' } }
My desired result is to get the generated SQL query.
Is there any wrong point? Is there any good way to get the SQL query?
.getQuery() or .getSql()
const sql1 = await this.attendanceRepository
.createQueryBuilder("attendance")
.innerJoin("attendance.child", "child")
.select(["attendance.childId","child.class","CONCAT(child.firstName, child.lastName)"])
.where("attendance.id= :id", { id: id })
.getQuery();
console.log(sql1);
const sql2 = await this.attendanceRepository
.createQueryBuilder("attendance")
.innerJoin("attendance.child", "child")
.select(["attendance.childId","child.class","CONCAT(child.firstName, child.lastName)"])
.where("attendance.id= :id", { id: id })
.getSql();
console.log(sql2);
printSql can also be used, but it will only print when logging is enabled.
#Module({
imports: [
TypeOrmModule.forRoot({
...options
logging: true
}),
],
})
await this.attendanceRepository
.createQueryBuilder("attendance")
.innerJoin("attendance.child", "child")
.select(["attendance.childId","child.class","CONCAT(child.firstName, child.lastName)"])
.where("attendance.id= :id", { id: id })
.printSql();

Sequelize mysql order by concat of two fields

My DB has a users table that has a first_name,last_name columns, either of them maybe empty.
I also have a UI dashboard that displays a table with a full_name column that is a concatenation of the two fields, this column is sortable.
I am using sequelize with a mysql database to fetch the users, how can I order by full_name (And trim the spaces of the concatenated field)
The SQL solution
You can order by multiple columns
SELECT * FROM user ORDER BY last_name ASC, first_name ASC
OR you first concatenate the two fields and order by full_name (but keep in mind this might be slow)
SELECT *, TRIM(CONCAT(first_name,' ', last_name)) full_name FROM user ORDER BY full_name ASC
The Sequelize solution
const { Sequelize, DataTypes } = require('sequelize')
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
first_name: {
type: DataTypes.STRING(100)
},
last_name: {
type: DataTypes.STRING(100)
},
//virtual attribute for concatenation of first_name and last_name
full_name: {
type: DataTypes.VIRTUAL,
get() {
const firstName = this.getDataValue('first_name');
const lastName = this.getDataValue('last_name');
return [firstName, lastName].join(' ').trim();
}
},
});
User.findAll({
/** Order by multiples columns **/
//order: [['first_name', 'DESC'], ['last_name', 'ASC']],
/** Order by the two fields concatenated and trimed */
order: Sequelize.literal("trim(concat(first_name,' ', last_name)) ASC")
}).then(users => {
users.forEach(user=> {
console.log(user.get());
})
})

Vue.js filter values from two store

I need help with getters in Vue.js, I'm trying to get list of data that is connected with id in two different stores.
Here is structure:
pageUser {
pageId,
userId,
type,
weight
}
user {
id,
name,
age,
city
}
This is code I have for now:
state: () => {
return {
images: [
{id: '1', name:'John', age: 23, city: 'Boston'},
{id: '2', name:'Jack', age: 34, city: 'Miami'}
]
}
},
getters: {
list: (state, pageId) => (key) => {
return map(state[key], function (s) {
return {
id: s.id,
name: s.name,
age: s.age,
city: s.city
}
})
}
This return me list of all users, but I need to make some filtering, when I go to page for example with id '2586' I need to get list of user that belong that page and they should be sorted by weight.
I'm pretty new in Vue.js and I really don't know how to make this.
getters: {
getUser: state => id => {
return user
// Create a new array of objects merging both the states
.map(u => {
return {
...pageUser.find(pu => pu.userId === u.id),
u
}
})
// Filter by id provided to the getter
.filter(u => u.id === id)
// Sort on basis of weight
.sort((a,b) => {
if (a.weight < b.weight) {
return -1
}
else if (a.weight > b.weight)) {
return 1
}
return 0
})
}
}
Call the getter in your component:
this.$store.getters.getUser('2586')