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
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;`);
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;
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();
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());
})
})
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')