Prisma: How can I implement a complex conditional query in Prisma? - sql

I have the following SQL query which I have to convert into a Prisma query but it seems that Prisma does not allow nested AND and OR query.How can the same be done?
SELECT *
FROM employees
WHERE (firstname LIKE '%Alex%' OR firstname LIKE '%Sean%')
AND (lastname LIKE '%Dennard%' OR lastname LIKE '%Joy%')
AND (age = 10)
AND (middlename LIKE 'Ali%' AND middlename NOT LIKE 'Alish')

You should be able to run this:
await prisma.employee.findMany({
where: {
AND: [
{
OR: [
{ firstname: { contains: "Alex" } },
{ firstname: { contains: "Sean" } },
],
},
{
OR: [
{ lastname: { contains: "Dennard" } },
{ lastname: { contains: "Joy" } },
],
},
{
age: 10,
},
// ...
],
},
});

Related

sql conversion to mongodb aggregate

I'm new to SQL and MongoDB. I'm trying to convert this:
SELECT accountType, ROUND(AVG(balance), 2) avgBalance
FROM customers
WHERE gender="female"
GROUP BY accountType
HAVING COUNT(*) < 140
ORDER BY avgBalance
LIMIT 1
to MongoDB but I can't get it to work. I don't quite understand how the order ($group, $match, $project, $round, $avg etc.) should be and how the "ROUND and AVG" are used together. This is how the answer should be like: { "accountType" : "account-type", "avgBalance" : NumberDecimal("9999.99") }
Here is what I have so far:
db.customers.aggregate( [ { $group: { _id: { accountType: "accountType", avgBalance: { $avg: { "balance" } } }, { $match: { count: { $lt: 140 } } }, { gender: "female" }, { $project: { "accountType": { $round: [ $agv: "balance", 2 ] } } }, { $limit: 1 } ] )
Direction is not bad, would be this one:
db.customers.aggregate([
// WHERE gender="female"
{ $match: { gender: "female" } },
// GROUP BY accountType, SELECT AVG(balance)
{
$group: {
_id: "$accountType",
avgBalance: { $avg: "$balance" },
count: {$sum: 1}
}
},
// HAVING COUNT(*) < 140
{ $match: { count: { $lt: 140 } } },
// SELECT ... AS ...
{
$project: {
accountType: "$_id",
avgBalance: { $round: ["$avgBalance", 2] }
}
},
// ORDER BY avgBalance
{ $sort: { avgBalance: 1 } },
// LIMIT 1
{ $limit: 1 }
])

Search Algorithm Implementation using NodeJS + MongoDB(or SQL)

There is an application with search input that gives an opportunity to search for contacts by their information stored in database.
For example, I can type 0972133122 Alan and my search engine must return all contacts whose firstname is Alan & whose numbers match 0972133122 string.
Of course, I can just type Alan 0972, for instance, and there must be returned all possible contacts matching this pattern. The query order may be different, so that I can type 0972 Alan Smith, and if there are 2 contacts with Alan names and whose phone numbers start with 0972, then additional Smith clarification should return the only 1 contact.
I suggest built in phone applications for Android make use of this search algorithm:
So that my goal is to achieve similar result, but I do know how to do this. Here my code:
GraphQL query
query contacts {
contacts(input: {
contactQuery: "Alan Smith"
}) {
name {
firstName
lastName
}
}
}
NodeJS query to MongoDB
const conditions = {};
const expr = contactQuery
.split(' ')
.map((contact) => new RegExp(`${contact}`, 'i'))
conditions.$or = [
{ 'firstName': { $in: expr } },
{ 'lastName': { $in: expr } },
{ 'university': { $in: expr } },
{ emails: { $elemMatch: { email: { $in: expr } } } },
{ phones: { $elemMatch: { phone: { $in: expr } } } },
{ socials: { $elemMatch: { id: { $in: expr } } } },
]
const contacts = await this.contacts
.find(conditions, undefined)
.exec()
This works partly, but I receive unwanted documents from MongoDB:
{
contacts: [
{
firstName: "Alan",
lastName: "Smith",
university: "KNTU",
...
},
{
firstName: "Alan",
lastName: "Alderson", // should not be returned
university: "ZNU",
...
},
...
]
}
But I need to get one contact that has strictly Alan firstname and Smith lastname. If it's impossible to do with MongoDB, -- please, provide me an example of SQL query. Any suggestions & solutions will be accepted!
Please, let me know if my question still is not clear.
Firstly, you need to separate out the numbers and words from the search text and then you can create a possible combination of it for an example:
FirstName: Alan, LastName: Smith
FirstName: Smith, LastName: Alan
Using regex you can do this easily and then you can use logical operators of mongodb to create your query like this
Approach 1
db.collection.find({
$or: [
{
$and: [
{
firstName: {
$regex: "Alan",
$options: "i"
}
},
{
lastName: {
$regex: "Smith",
$options: "i"
}
}
]
},
{
$and: [
{
firstName: {
$regex: "Smith",
$options: "i"
}
},
{
lastName: {
$regex: "Alan",
$options: "i"
}
}
]
}
]
})
Here is the link to the playground for you to look at it in action Mongo Playground
Approach 2
Another way is where you concat all the searchable keys into one field and then use regex to filter it out like this
db.collection.aggregate([
{
$addFields: {
text: {
$concat: [
"$firstName",
" ",
"$lastName",
" ",
"$university",
" ",
"$phones"
]
}
}
},
{
$match: {
text: {
$regex: "(?=.*?(0972))(?=.*?(Alan))(?=.*?(Smith))",
$options: "i"
}
}
},
{
$project: {
text: 0
}
}
])
Code to build the query:
let text = "0972 Alan Smith";
let parts = text.split(" ");
let query = parts.map(part => "(?=.*?("+part+"))").join("");
console.log(query);
But you need to check the performance implication of this approach or you can create a view and then query to view to make your query more cleaner
Here is the link to the playground for you to look at it in action Mongo Playground

TypeORM "OR" operator

I could not find any notion of OR operator neither in TypeORM docs nor in the source code. does it support it at all?
I'm trying to do perform a basic search with a repository.
db.getRepository(MyModel).find({
name : "john",
lastName: "doe"
})
I know this generates an AND operation but
I need an OR operation so SQL would look like:
name='john' OR lastName='doe'
Am I forced to use the query builder for something basic like this?
db.getRepository(MyModel).find({
where: [
{ name: "john" },
{ lastName: "doe" }
]
})
Pass an array to where
I had the same issue, but I worked around it with the QueryBuilder.
This would be an example.
return await getRepository(MyModel)
.createQueryBuilder()
.where("name = :name OR lastName = :lastName", {
name: "john",
lastName: "doe"
})
.getMany();
To use OR in sub-clause, I have to repeat the main-clause
userRepository.find({
where: [
{
firstName: 'Timber',
lastName: 'Saw',
project: {
name: 'TypeORM',
},
},
{
firstName: 'Timber',
lastName: 'Saw',
project: {
initials: 'TORM',
},
},
],
});
Find all Timber Saw have projects with name = "TypeORM" or initials = "TORM"
You can combine "OR" sub-clause with additional "AND" by doing the following.
db.getRepository(MyModel).find({
where: [
{ name: "john", lastName: "doe" },
{ age: 20 }
]
})
This would result to
select * from model where (name = "john" and lastname = "doe") OR age = 20
Hope this helps.

Mongodb: get count of multiple values in a field grouped by another field

I have a collection as below
{"country":"US","city":"NY"}
{"country":"US","city":"AL"}
{"country":"US","city":"MA"}
{"country":"US","city":"NY"}
{"country":"US","city":"MA"}
{"country":"IN","city":"DL"}
{"country":"IN","city":"KA"}
{"country":"IN","city":"DL"}
{"country":"IN","city":"DL"}
{"country":"IN","city":"KA"}
and expecting an output
{ "data": { "US": {"NY": 2,"AL": 1,"MA": 2 },
"IN": {"DL": 3,"KA": 2 }}
}
Below is the mongodb query I tried, i was able to get to get the count at country level, but not at the state level. please help me in correcting the below query to get data at state level.
db.country_dash.aggregate([
{"$group": {
"_id":"$country",
"state": {"$addToSet": "$state"}
}},
{"$project": {
"_id":0,
"country":"$_id",
"state": {"$size": "$state"}
} }
])
db.country_dash.aggregate(
// Pipeline
[
// Stage 1
{
$group: {
_id: {
city: '$city'
},
total: {
$sum: 1
},
country: {
$addToSet: '$country'
}
}
},
// Stage 2
{
$project: {
total: 1,
country: {
$arrayElemAt: ['$country', 0]
},
city: '$_id.city',
_id: 0
}
},
// Stage 3
{
$group: {
_id: '$country',
data: {
$addToSet: {
city: '$city',
total: '$total'
}
}
}
},
]
);

SQL to sequelize orm query change

SQL query is working fine but in node js using suquelize orm query not working.
SQL : Woking Fine
select message from tbl_chat where (userId=1 or userId=98) and (receiverId=1 or receiverId=98) and isgroupChat=0;
Sequelize ORM : Not working
let result = await Chat.findAll<Chat>({
where: {
isgroupChat: 0,
$and: {
$or: [
{
userId: userId
},
{
userId: userId
}
],
$or: [
{
receiverId: receiverId
},
{
receiverId: receiverId
}
]
}
}
});
Not sure why exactly this isn't working. Turn on logging and see what the ORM is producing for a query. But, I'd also try changing the query a little:
{
where: {
isGroupChat: 0,
userId: { $in: [uid1, uid2] },
receiverId: { $in: [uid1, uid2] }
}