sql - 使用 NodeJS + MongoDB(或 SQL)实现搜索算法
问题描述
有一个带有搜索输入的应用程序,它提供了通过存储在数据库中的信息来搜索联系人的机会。
例如,我可以键入0972133122 Alan
,并且我的搜索引擎必须返回firstname
其Alan
号码与0972133122
字符串匹配的所有联系人。
当然,Alan 0972
例如,我可以只键入 ,并且必须返回与此模式匹配的所有可能联系人。查询顺序可能不同,因此我可以输入0972 Alan Smith
,如果有 2 个联系人的Alan
姓名和电话号码以 开头0972
,那么额外Smith
的说明应该返回唯一的 1 个联系人。
我建议内置的 Android 手机应用程序使用这种搜索算法:
这样我的目标是达到类似的结果,但我知道如何做到这一点。这是我的代码:GraphQL 查询
query contacts {
contacts(input: {
contactQuery: "Alan Smith"
}) {
name {
firstName
lastName
}
}
}
NodeJS 查询到 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()
这部分有效,但我从 MongoDB 收到不需要的文档:
{
contacts: [
{
firstName: "Alan",
lastName: "Smith",
university: "KNTU",
...
},
{
firstName: "Alan",
lastName: "Alderson", // should not be returned
university: "ZNU",
...
},
...
]
}
但我需要得到一个严格Alan
firstname
和Smith
lastname
. 如果无法使用 MongoDB,请提供一个 SQL 查询示例。任何建议和解决方案都将被接受!
如果我的问题仍然不清楚,请告诉我。
解决方案
首先,您需要从搜索文本中分离出数字和单词,然后您可以创建一个可能的组合,例如:
- 名字:
Alan
,姓氏:Smith
- 名字:
Smith
,姓氏:Alan
使用正则表达式,您可以轻松地做到这一点,然后您可以使用logical operators
来mongodb
创建这样的查询
方法一
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"
}
}
]
}
]
})
这是 Playground 的链接,您可以在Mongo Playground中查看它
方法二
另一种方法是将concat
所有可搜索的键放入一个字段中,然后使用正则表达式将其过滤掉
db.collection.aggregate([
{
$addFields: {
text: {
$concat: [
"$firstName",
" ",
"$lastName",
" ",
"$university",
" ",
"$phones"
]
}
}
},
{
$match: {
text: {
$regex: "(?=.*?(0972))(?=.*?(Alan))(?=.*?(Smith))",
$options: "i"
}
}
},
{
$project: {
text: 0
}
}
])
构建查询的代码:
let text = "0972 Alan Smith";
let parts = text.split(" ");
let query = parts.map(part => "(?=.*?("+part+"))").join("");
console.log(query);
但是您需要检查这种方法的性能影响,或者您可以创建一个view
然后查询来查看以使您的查询更清晰
这是 Playground 的链接,您可以在Mongo Playground中查看它
推荐阅读
- python - 如何从 csv 读取第一列并分成多维数组
- python - xarray - 使用 groupby 对一年中的每一天的气候每小时 netCDF 数据进行分组
- node.js - 猫鼬突然坏了,没有得到回调
- loops - 将整数值相加并在不同的类中使用它们
- html - 如何影响 HTML5 进度元素的最小宽度?
- azure - 具有恢复服务保管库位置的 Azure 存储帐户位置
- sql - 如何使用 case 语句使用计数
- asp.net-core - 无法将 ASP.NET Core 的 IdentityServer4 代码示例托管为 Windows 服务
- sql - 在变量列中用名称加入/替换 ID
- amazon-web-services - DynamoDB 仅按二级索引查询