In my Node application we have used Sequelize to connect with mysql
Have two table User & UserOption
User table have following fields
user_id(pk)
user_email
UserOption table have following fields
option_id(pk)
user_id(fk)
first_name
I need to list all user by search text in user_email & first_name
Is there any option to search both parent & child table fields in Sequelize?
UPDATE
User table
user_id user_email
1 text#text.com
2 anything#anything.com
3 jhon#smthng.com
UserOption table
option_id user_id first_name
1 1 jhon
2 2 smith
3 3 david
If I search for "jhon", the result will be both user with id 1 and 2
You need to include model UserOption in lookup on model User. This generates a JOIN clause with condition UserOption.user_id = User.user_id, as well as adds specified WHERE clause to perform text lookup on user_email and first_name columns of both tables
User.findAll({
where: {
user_email: { $like: '%text%' }
},
include: [
{
model: UserOption,
where: {
first_name: { $like: '%text%' }
},
attributes: []
}
]
}).then((users) => {
// result
});
EDIT
Basing on your updated question, I think that you can try using sequelize.literal method, but, according to the documentation:
Creates a object representing a literal, i.e. something that will not be escaped.
So it is necessary to escape desired values by yourself
let escValue = sequelize.escape(lookupText);
User.findAll({
where: {
$or: [
{ email: { $like: '%' + lookupText + '%' },
{ id: { $in: sequelize.literal(`(SELECT uo.user_id FROM user_options uo WHERE uo.first_name LIKE CONCAT('%', ${escValue}, '%'))`) }
]
}
}).then((users) => {
// result...
});
It would generate a query which selects users from users table where email LIKE '%text%' or where users.id is in specified query result.
I am very curious if this satisfies your needs, waiting for feedback.
Related
I want to replicate this MySQL query in Sequelize:
select u.email, a.serverId, ak.apikey from users u
join accounts a on u.id = a.userId
join apikeys ak on ak.userId = u.id
where u.state = "active" and ak.state = 1 and a.serverId = ak.serverId
This is my translation, except for the final and clause (a.serverId = ak.serverId) which I'm not sure how to achieve:
const activeKeys = await models.User.findAll({
attributes: ['email'],
raw: true,
where: {
state: "active"
},
include: [{
model: models.Account,
attributes: ['serverId']
},
{
model: models.Apikey,
attributes: ['apikey'],
where: {
state: 1
}
}]
})
I've tried multiple combinations of associations, these are the current ones:
db.Account.belongsTo(db.User) // account has 1 user
db.User.hasMany(db.Account) // user has multiple accounts
db.User.hasMany(db.Apikey) // user has multiple apikeys
db.Apikey.belongsTo(db.User) // apikey has 1 user
db.Apikey.hasMany(db.Account) // apikey has many accounts
db.Account.hasOne(db.Apikey) // account has 1 apikey
The only part that is missing is the and clause between the 2 included models. How can I achieve it?
Try something like this in the main where:
where: Sequelize.and(
Sequelize.where(Sequelize.col("state"), "=", "active"),
Sequilize.where(Sequelize.col("Account.serverId"),"=", Sequelize.col("Apikey.serverId"))
)
this.sampleRepo.find(
{
order: {
id: "DESC"
},
select: ['id','group']
}
);
this returns the id and group as expected, but how to return id as user_id ?
and also how to select distinct values from group?
Just add an alias in you select string, e.g.:
select: ['id AS user_id','group AS user_group']
If the previous option didn't work, it should work in queryBuilder:
this.sampleRepo
.createQueryBuilder('user')
.orderBy('user.id', 'DESC')
.select(['id AS user_id','group AS user_group'])
.getRawMany() // or .getMany()
I've made smth as you need with one of my examples (last one here) but wrote this (upd. fixed with getRawMany and distinct):
getMany(): Promise<UserEntity[]> {
return this.userRepo.createQueryBuilder('user')
.where({ username: 'breckhouse0' })
.select(['DISTINCT (user.username) AS user_name', 'user.id AS user_id'])
.getRawMany();
}
and this works as you expect - results
SQL statement 1
const [rows, fields] = await pool.query("SELECT * FROM accounts WHERE username = ?", username);
console.log(rows);
return rows
SQL statement 2
const [rows, fields] = await pool.query("SELECT * FROM accounts WHERE id = ?", id);
console.log(rows)
return rows
It is the same database but the result I am getting back is displayed differently.
For the query for username,
[
TextRow {
id: 8,
username: 'testing',
password: '-',
aws_id: '-',
timestamp: 2020-02-23T23:38:06.000Z
}
]
For the query by id
{
'0': TextRow {
id: 8,
username: 'testing',
password: '-',
aws_id: '-',
timestamp: 2020-02-23T23:38:06.000Z
}
}
Why is it that when I am querying with ID, there is a "0" key appended to it.
Its possible that because id is unique, the results will never be a list of items, and "whatever you're using to connect to mysql" automatically formats for that.
some browsers also routinely add indexes to json that arent actually in the data. make sure you're not following a false-positive here and use "raw data" to view it
Given Users table and Ratings table
How do I query all user records from Users table that does not have any rating record in Ratings table using Sequelize include clause
Note: Sequelize version 5.x
Thanks in advance
You can do this in two ways depending on how your models are defined.
1. Get all Users along with Ratings by using Sequelize Eager Loading. Then filter where user does not have any ratings.
const users = Users.findAll({
include: [Ratings]
});
const filteredUsers = users.filter(user => user.ratings.length === 0);
2. Get all userIds from the Ratings table and then pass these userIds to the where clause using the notIn Sequelize operator
const ratings = Ratings.findAll({
attributes: ["userId"],
group: ["userId"]
});
const userIds = ratings.map(rating => rating.userId);
const filteredUsers = Users.findAll({
where: {
userId: { [Op.notIn]: userIds }
}
});
Try incorporating a sequelize literal in the where clause:
const ratings = Ratings.findAll({
attributes: ["userId"],
group: ["userId"],
where: {
$and: [
sequelize.literal(`NOT EXISTS (
SELECT 1 FROM Ratings r
WHERE r.userId = User.id
)`),
],
},
});
Assuming you have a relationship between Users and Ratings in your models, this can be accomplished in a single query by using a left outer join followed by a filter on the client side.
In your model definition:
Users.hasMany(Ratings, { foreignKey: 'user_id' });
Ratings.belongsTo(Users, { foreignKey: 'user_id' });
In your query:
const users = await Users.findAll({
include: [
{
model: Ratings,
required: false // left outer join
}
]
});
const usersWithoutRatings = users.filter(u => u.user_ratings.length === 0);
I have a front end with a singular input to search names however my database separated them into 2 fields. What I want to do is run a concat and like statement alone the lines of:
SELECT * FROM users WHERE (CONCAT(first_name, ' ', last_name)) LIKE '%John Do%' AND permission_id = 1 AND user_status_id = 1;
now I've gotten to this:
let name = req.params.name;
let userId = req.user;
debugger;
db.user.findAll({
where: {
attributes: [db.sequelize.fn('concat', db.Sequelize.col('first_name'), ' ', db.Sequelize.col('last_name'), 'full_name'), {
like: `%${name}%`
}],
},
include : [
db.client
]
})
but can't think where to include the like or the concat