Sequelize - Nested wheres overriding eachother - javascript

Considering this request (ran against Postgres)
var customers = await database.Customer.findAll({
attributes: [ 'idcustomer', 'firstname', 'lastname' ],
include: [
{
model: database.Telephone, as: "Telephones",
attributes: [ 'number' ],
where: { number: { [database.sequelize.Op.eq]: req.body.telephone } }
}
],
where: { [database.sequelize.Op.or]: [
{ firstname: { [database.sequelize.Op.iLike]: req.body.firstname} },
{ lastname: { [database.sequelize.Op.iLike]: req.body.lastname} },
{ email: { [database.sequelize.Op.iLike]: req.body.email } }
] }
});
What i'm trying to achieve is query for customers by first&last name/email/telephone number, let's call them F, L, E and T. This query basically selects all users where T & (F | L | E), however, what I'm trying to get to is (F | L | E | T).
The bottom where parameter in the code filters prepends "Customer." to the parameters so grouping the number with the rest of the comparisons is not possible. Is there a workaround for this?
Generated SQL:
SELECT
"Customer"."idcustomer", "Customer"."firstname", "Customer"."lastname",
"Telephones"."number" AS "Telephones.number"
FROM "Customer" AS "Customer"
INNER JOIN "Telephone" AS "Telephones"
ON "Customer"."idcustomer" = "Telephones"."customer" AND "Telephones"."number" = ''
WHERE
("Customer"."firstname" ILIKE '' OR "Customer"."lastname" ILIKE '' OR "Customer"."email" ILIKE '');

You can use Sequelize.col() to reference the included row :
var customers = await database.Customer.findAll({
attributes: [ 'idcustomer', 'firstname', 'lastname' ],
include: [
{
model: database.Telephone,
as: "Telephones",
attributes: [ 'number' ]
}
],
where: { [database.sequelize.Op.or]: [
{
telephone: Sequelize.where(Sequelize.col(`"Telephones".number`), {
[database.sequelize.Op.eq]: req.body.telephone
})
},
{ firstname: { [database.sequelize.Op.iLike]: req.body.firstname} },
{ lastname: { [database.sequelize.Op.iLike]: req.body.lastname} },
{ email: { [database.sequelize.Op.iLike]: req.body.email } }
] }
});

Related

Search query String Array Object in mongoose and use elemMatch is not working as expected

I am facing with an error which I am unable to resolve it.
I want to use query search to search if the data of 1 job matches with user data but I am stucked in some cases.
First case it is that my query search of the job looks like this I mean the data.
The problem it is that in the searchFilterSkills.searchSkillsOffer I have an array of objects and I want to match the name of each of them if one of them exist but I am unable to iterate through them because I get an array of Strings with .map() which cannot iterate on it.
After answer from Fabian if all elements matches it returns the elements and it matches but I want if 1 of the elements matches it will return the object.
I tried $in but did not work. Is there any query to use instead of $all
These are my data which I try to search.
"skillsOffer":[
{
"name":"Max",
"rate":0
},
{
"name":"Test",
"rate":0
},
{
"name":"Javascript",
"rate":0
}
],
"country":"DEU",
"postalCode":12345
And these are the user Data which he/she has.
"searchFilter" : {
"remote" : 0,
"data" : [
{
"region" : [
"1"
],
"country" : "DEU",
"searchActive" : false,
"postalCode" : "123",
"available" : {
"$date" : 1664955924380
}
}
]
},
"searchFilterSkills" : {
"searchSkillsOffer" : [
{
"name" : "Javascript",
"rate" : 100
},
{
"name" : "Test",
"rate" : 60
},
{
"name" : "Client",
"rate" : 0
}
],
}
At skillsOffer I want to search if only the name matches not the rate.
Then if remote is 1 then search the above query and without postalCode with remote or the above one and remote.
async searchUsers(req, res, next) {
const jobID = req.query.jobID;
let job = await Job.findById(jobID);
let postalCode = job.postalCode;
postalCode = postalCode.toString().slice(0, 1);
let postalCode2 = job.postalCode;
postalCode2 = postalCode2.toString().slice(0, 2);
let postalCode3 = job.postalCode;
postalCode3 = postalCode3.toString().slice(0, 3);
let postalCode4 = job.postalCode;
postalCode4 = postalCode4.toString().slice(0, 4);
let postalCode5 = job.postalCode;
postalCode5 = postalCode5.toString().slice(0, 0);
let userIds = job.skillsOffer.map(user => user.name).join(",");
let users = await User.find({
"searchFilter.data": {
$elemMatch: {
"$or": [
{
postalCode: postalCode,
},
{
postalCode: postalCode2,
},
{
postalCode: postalCode3,
},
{
postalCode: postalCode4,
},
{
postalCode: postalCode,
},
{
postalCode: postalCode5,
},
]
}
},
"searchFilter.data": {
$elemMatch: {
country: job.country
}
},
'searchFilterSkills.searchSkillsOffer': {
$elemMatch: {
name: {
$regex: new RegExp(`^${job.skillsOffer.map(jt => jt.name)}`, 'i'), but it does not return a thing here
},
},
},
});
if (job.remote.toString() === "1") {
users = await User.find({
"searchFilter.data": {
$elemMatch: {
"$or": [
{
postalCode: postalCode,
},
{
postalCode: postalCode2,
},
{
postalCode: postalCode3,
},
{
postalCode: postalCode4,
},
{
postalCode: postalCode,
},
{
postalCode: postalCode5,
},
]
}
},
"searchFilter.data": {
$elemMatch: {
country: job.country
}
},
"searchFilter.remote": job.remote,
});
}
if (!users) {
res.status(204).json({ error: "No Data" });
return;
}
return res.status(200).send({
user: users.map(t =>
t._id
)
});
},
I assume you want to match each name from skillsOffer array. This way you have to define an $elemMatch object for each name (basically mapping each name).
You can use the following (partial) query in your code in order to check whether all names are contained in your searchFilterSkills.searchSkillsOffer array.
{
'searchFilterSkills.searchSkillsOffer': {
$all: job.skillsOffer
.map((user) => user.name)
.map((name) => ({
$elemMatch: {
name: {
$regex: new RegExp(`^${name}$`, 'i'),
},
},
})),
},
}
If you would like to match any name, you should or the following code:
{
$or: job.skillsOffer
.map((user) => user.name)
.map((name) => ({
'searchFilterSkills.searchSkillsOffer': {
$elemMatch: {
name: {
$regex: new RegExp(`^${name}$`, 'i'),
},
},
},
})),
}

Sequelize search "Unknown column 'contact.name' in where clause

I have a service that is in charge of bringing the tickets with the last message of the users.
For this, the Contact, Queue, WhatsApp models were added to the include.
The problem is that when adding the Tags model, closely related to "Contact", the service stopped working and response with:
"Unknown column 'contact.name' in where clause
The only thing I added was the relationship with Tags, since it is new. Help me understand? It's like it no longer recognizes the column
interface Request {
searchParam?: string;
pageNumber?: string;
status?: string;
date?: string;
showAll?: string;
userId: string;
withUnreadMessages?: string;
queueIds: number[];
}
interface Response {
tickets: Ticket[];
count: number;
hasMore: boolean;
}
const ListTicketsService = async ({
searchParam = "",
pageNumber = "1",
queueIds,
status,
date,
showAll,
userId,
withUnreadMessages
}: Request): Promise<Response> => {
let whereCondition: Filterable["where"] = {
[Op.or]: [{ userId }, { status: "pending" }],
queueId: { [Op.or]: [queueIds, null] }
};
let includeCondition: Includeable[];
includeCondition = [
{
model: Contact,
as: "contact",
attributes: ["id", "name", "number", "profilePicUrl"],
include: [{
model: Tags,
as: "tags",
attributes: ["name"],
}]
},
{
model: Queue,
as: "queue",
attributes: ["id", "name", "color"]
},
{
model: Whatsapp,
as: "whatsapp",
attributes: ["name"]
},
];
if (showAll === "true") {
whereCondition = { queueId: { [Op.or]: [queueIds, null] } };
}
if (status) {
whereCondition = {
...whereCondition,
status
};
}
if (searchParam) {
const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
includeCondition = [
...includeCondition,
{
model: Message,
as: "messages",
attributes: ["id", "body"],
where: {
body: where(
fn("LOWER", col("body")),
"LIKE",
`%${sanitizedSearchParam}%`
)
},
required: false,
duplicating: false
}
];
whereCondition = {
...whereCondition,
[Op.or]: [
{
"$contact.name$": where(
fn("LOWER", col("contact.name")),
"LIKE",
`%${sanitizedSearchParam}%`
)
},
{ "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } },
{
"$message.body$": where(
fn("LOWER", col("body")),
"LIKE",
`%${sanitizedSearchParam}%`
)
}
]
};
}
if (date) {
whereCondition = {
createdAt: {
[Op.between]: [+startOfDay(parseISO(date)), +endOfDay(parseISO(date))]
}
};
}
if (withUnreadMessages === "true") {
const user = await ShowUserService(userId);
const userQueueIds = user.queues.map(queue => queue.id);
whereCondition = {
[Op.or]: [{ userId }, { status: "pending" }],
queueId: { [Op.or]: [userQueueIds, null] },
unreadMessages: { [Op.gt]: 0 }
};
}
const limit = 40;
const offset = limit * (+pageNumber - 1);
const { count, rows: tickets } = await Ticket.findAndCountAll({
where: whereCondition,
include: includeCondition,
distinct: true,
limit,
offset,
order: [["updatedAt", "DESC"]], logging: console.log
});
const hasMore = count > offset + tickets.length;
return {
tickets,
count,
hasMore
};
};
export default ListTicketsService;
Another thing is, i don't know how but this is giving me only unique record. The problem is, 1 contact may have n Tags. So, its possible do this query?
Regards

Sequelize include nested column: Unknown column in 'where clause'

I am trying to use the Sequelize ORM's feature that allows referring the nested column from the included Models (See Sequelize Docs: Complex where clauses at the top-level). In the docs it states that, I can use $nested.column$ syntax.
The following is what I was trying to do:
let where = { memberId };
if (req.query.search) {
const like = { [Op.like]: `%${req.query.search}%` };
where = {
...where,
[Op.or]: [
{ '$bookItem.serial$': like },
{ '$bookItem.book.name$': like },
{ '$bookItem.book.ISBNCode$': like },
],
};
}
const options = {
where,
include: [
{
model: models.BookItem,
as: 'bookItem',
required: false,
include: [
{
model: models.Book,
as: 'book',
attributes,
required: false,
},
],
},
],
});
const transactions = await models.Borrow.findAll(options);
However, for the code above, I am getting the following error:
"Unknown column 'bookItem.serial' in 'where clause'"
What am I missing?
Full DB Schema: https://dbdiagram.io/d/5e08b6aaedf08a25543f79cb
Is bookitem a Table? Or a Database?
bookItem.serial either represents db.tbl or tbl.column
bookItem.book.name can only represent db.tbl.column
Since bookItem seems to be a database name, then serial must be a table name. At that point, "tablename LIKE ..." is a syntax error.
In your linked documentation books has no name column, change $bookItem.book.name$ to $bookItem.book.title$, and try adding right: true below required: false to create an inner join.
I have corrected this error on my side. Initially, I am writing this query
but now I have rearranged the query and it works
WRONG QUERY
let where = {
[op.and]: [
{ id: partner_id },
{ [op.or]: [
{ '$customers.customer_name$': { [op.like]: '%' + query + '%'} },
{ '$customers.email$': { [op.like]: '%' + query + '%'} },
]},
],
};
// const where = {
// id: partner_id
// }
return await this.deliveryBoys.findOne({
attributes: [
['id', 'partner_id'],
'delivery_boy_name',
'email',
'profile_picture',
'phone_number',
'fcm_token',
],
include: [
{
model: this.customers,
as: 'customers',
attributes: ['id', 'customer_name', 'email', 'profile_picture', 'phone_number'],
require: true,
where: {
customer_name: {
[op.like]: '%' + query + '%'
}
},
include: [
{
model: this.company,
as: 'company',
},
{
model: this.address,
as: 'address',
required: false,
where: {
status: 1
}
}
]
},
],
where,
});
FINAL WORKING QUERY
let where = {
[op.and]: [
{ '$deliveryBoys.id$': partner_id },
{ [op.or]: [
{ '$customers.email$': { [op.like]: '%' + query + '%'} },
{ '$customers.customer_name$': { [op.like]: '%' + query + '%'} },
{ '$customers.phone_number$': { [op.like]: '%' + query + '%'} },
{ '$company.name$': { [op.like]: '%' + query + '%'} },
]},
],
};
return await this.customers.findAll({
attributes: ['id', 'customer_name', 'email', 'profile_picture', 'phone_number'],
include:[
{
model: this.deliveryBoys,
as: 'deliveryBoys',
attributes: ['id','delivery_boy_name','phone_number','email','profile_picture','status',],
where:{
id: partner_id
}
},
{
model: this.company,
as: 'company',
},
{
model: this.address,
as: 'address',
required: false,
where: {
status: 1
}
}
],
where
});

How do you filter multiple related records using prisma?

Here is my sample filter, but unfortunately this doesn't work, I'm just wondering if there is a way to filter multiple related records in Prisma?
This is my sample schema:
model SalesReport {
id String #id #default(uuid())
dateCreated DateTime #default(now())
name String
tin String?
// salesStaff
salesStaff SalesStaff[]
}
SOLVED:
{
skip: 0,
orderBy: {
name: 'desc'
},
where: {
AND: [
{
salesStaff: {
some: {
AND: [
{
id: {
equals: 'fe4a3704-67a3-4a09-8471-18a95ee22bd0'
}
},
{
id: {
equals: 'z24a3712-67a3-4a09-8471-18a95ee22bd1'
}
}
]
}
}
}
],
},
}
I only need to put the AND inside some to filter multiple times on a related record (silly me)
Using AND inside some helped me solve the problem, hehe.
{
skip: 0,
orderBy: {
name: 'desc'
},
where: {
AND: [
{
salesStaff: {
some: {
AND: [
{
id: {
equals: 'fe4a3704-67a3-4a09-8471-18a95ee22bd0'
}
},
{
id: {
equals: 'z24a3712-67a3-4a09-8471-18a95ee22bd1'
}
}
]
}
}
}
],
},
}

Angular & Mongo query , return result closely equal to related to the search keyword

If text(firstname) == 'Eric' , it should return results . Any idea how we can tweek my code to return result as expected on the example ?
I am using angular on the front-end.
#Expected result (this would be top on the result)
Eric Gluthner
Eric Lecher
Erick Laspin
#and the other names with eric which would be less prio
Derick Ramp
Daniel Ericto
Raerick Fouler
#Code
getData(text: string): Observable<Identity[]> {
const search_query = {
query: {
$or: [
{ firstName: { $like: text } },
{ email: { $like: text } },
],
status: 1,
$sort: {
firstName: 1
},
// $limit: 5,
}
};
Using $regex pattern matching
getData(text: string): Observable<Identity[]> {
const search_query = {
query: {
$or: [
{ firstName: { $regex: RegExp('^' + text) } },
{ email: { $like: text } },
],
status: 1,
$sort: {
firstName: 1
},
// $limit: 5,
}
};

Categories

Resources