Search Algorithm Implementation using NodeJS + MongoDB(or SQL) - 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

Related

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

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,
},
// ...
],
},
});

What is this mean in GrqphQL Expected type '[OrderCreationNotificationEnum!]

I have a service who provided me api to use and they are using GraphQL.
Everything else seems working fine apart from this section.
I'm using the following query to create an order and it's working fine apart from when I add notifications in there
I'm getting this error
Argument 'notifications' on InputObject 'OrderCreateMutationInput' has an invalid value ({type: {OrderCreationNotificationEnum: {email: true}}}). Expected type '[OrderCreationNotificationEnum!]'
mutation{
orderCreate(input: {
order: {
externalIds:[
{key: "VRPOrderId", value: "abc131"}
]
firstName: "John"
surname: "Doe"
phone: "0405123456"
billingFirstName: "John"
billingSurname: "Doe"
billingEmailAddress: "john#email.com"
address: {
address: "1 Bourke Street"
city: "Melbourne"
country: {
code: "AU"
}
postcode: "3000"
state: {
short: "VIC"
}
}
billingAddress:{
address: "1 Bourke Street"
city: "Melbourne"
country: {
code: "AU"
}
postcode: "3000"
state: {
short: "VIC"
}
}
termsAndConditionsAccepted: true
}
lineItems: [
{
variantId: "VmFyaWFudC00NzMz"
quantity: 1
totalCents: 22500
postageCents: 1000
},
{
variantId: "VmFyaWFudC00NzYy"
quantity: 1
totalCents: 22500
postageCents: 500
}
]
notifications:
{
type: {
OrderCreationNotificationEnum: {
email: true
}
}
}
})
{
order{
id
invoices{
edges{
node{
id
lineItems{
id
quantity
}
}
}
}
}
status
}
}
I am struggling to get the notification working. I'm adding link for the instructions too. Please help.
link to api document
Argument 'notifications' on InputObject 'OrderCreateMutationInput' is an Enum:
enum OrderCreationNotificationEnum {
# Notify the order information via Email
EMAIL
# Notify the order information via SMS
SMS
}
For notifications, you should specify an array of enum values like this:
notifications: [EMAIL, SMS]

Check value on a particular array index in Vuelidate

I have the following form array in Vuelidate. But how can I base some validation based on another field's value on the same array index.
Below is my none working example, but I want the forename to be required IF something has been entered for the surname.
validations: {
fixturesArray: {
$each: {
fixtureName: {
//required
},
guestDetails: {
$each: {
forename: {
required: requiredIf(function() {
return $each.surname != ""
})
},
surname: {
},
dietaryRequirements: {
$each: {
name: {
}
}
}
}
}
}
}
},
let's assume your case is: Forename is required if surname is not null
validations: {
fixturesArray: {
$each: {
guestDetails: {
$each: {
forename: {
requiredIf: requiredIf((obj) => obj.surname != null)
},
surname: {
}
}
}
}
}
}
You can use requiredIf in $each like that, although this is not stated in the documentation. The obj parameter is the object being validated in this iteration. You can see more information here.
Hope it helps, cheers.

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.

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] }
}