mongoose-fuzzy-searching 是一个简单且轻量级的插件,可以在 MongoDB 中的文档中进行模糊搜索。该代码基于这篇文章。
使用 npm 安装
$ npm i mongoose-fuzzy-searching
或使用纱线
$ yarn add mongoose-fuzzy-searching
在开始之前,为了获得最佳实践并避免任何问题,请正确处理所有弃用警告。
为了让插件创建索引,您需要将useCreateIndex
设置为 true。下面的例子演示了如何连接数据库。
const options = {
useNewUrlParser : true ,
useUnifiedTopology : true ,
useFindAndModify : false ,
useCreateIndex : true ,
} ;
mongoose . Promise = global . Promise ;
return mongoose . connect ( URL , options ) ;
在下面的示例中,我们有一个User
集合,我们希望在firstName
和lastName
中进行模糊搜索。
const { Schema } = require ( 'mongoose' ) ;
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
age : Number ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
const User = mongoose . model ( 'User' , UserSchema ) ;
module . exports = { User } ;
const user = new User ( { firstName : 'Joe' , lastName : 'Doe' , email : '[email protected]' , age : 30 } ) ;
try {
await user . save ( ) ; // mongodb: { ..., firstName_fuzzy: [String], lastName_fuzzy: [String] }
const users = await User . fuzzySearch ( 'jo' ) ;
console . log ( users ) ;
// each user object will not contain the fuzzy keys:
// Eg.
// {
// "firstName": "Joe",
// "lastName": "Doe",
// "email": "[email protected]",
// "age": 30,
// "confidenceScore": 34.3 ($text meta score)
// }
} catch ( e ) {
console . error ( e ) ;
}
结果按confidenceScore
键排序。您可以覆盖此选项。
try {
const users = await User . fuzzySearch ( 'jo' ) . sort ( { age : - 1 } ) . exec ( ) ;
console . log ( users ) ;
} catch ( e ) {
console . error ( e ) ;
}
选项可以包含fields
和middlewares
。
Fields 属性是强制性的,并且应该是Strings
数组或Objects
数组。
如果您想对所有字段使用默认选项,只需将它们作为字符串传递即可。
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
如果您想要覆盖参数的任何默认选项,您可以将它们添加为对象并覆盖您想要的任何值。下表包含该对象的预期键。
钥匙 | 类型 | 默认 | 描述 |
---|---|---|---|
姓名 | 细绳 | 无效的 | 集合键名 |
最小尺寸 | 整数 | 2 | N 克最小尺寸。了解有关 N 元语法的更多信息 |
重量 | 整数 | 1 | 表示该字段相对于其他索引字段在文本搜索分数方面的重要性。了解有关指数权重的更多信息 |
仅前缀 | 布尔值 | 错误的 | 只返回从单词开头开始的 ngram。 (它给出更精确的结果) |
逃脱特殊字符 | 布尔值 | 真的 | 从 N 元语法中删除特殊字符。 |
键 | 数组[字符串] | 无效的 | 如果集合属性的类型是Object 或[Object] (参见示例),则可以定义哪些属性将用于模糊搜索 |
例子:
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
content : {
en : String ,
de : String ,
it : String
}
text : [
{
title : String ,
description : String ,
language : String ,
} ,
] ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [
{
name : 'firstName' ,
minSize : 2 ,
weight : 5 ,
} ,
{
name : 'lastName' ,
minSize : 3 ,
prefixOnly : true ,
} ,
{
name : 'email' ,
escapeSpecialCharacters : false ,
} ,
{
name : 'content' ,
keys : [ 'en' , 'de' , 'it' ] ,
} ,
{
name : 'text' ,
keys : [ 'title' , 'language' ] ,
} ,
] ,
} ) ;
中间件是一个可选Object
,可以包含自定义pre
中间件。该插件使用这些中间件来创建或更新模糊元素。这意味着如果您添加pre
中间件,它们将永远不会被调用,因为插件会覆盖它们。为了避免这个问题,您可以将自定义中间件传递到插件中。您的中间件将首先被调用。您可以传递的中间件有:
schema.pre("save", ...)
schema.pre("insertMany", ...)
schema.pre("update", ...)
schema.pre("updateOne", ...)
schema.pre("findOneAndUpdate", ...)
schema.pre("updateMany", ...)
如果你想添加上面的任何中间件,可以直接在插件上添加。
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [ 'firstName' ] ,
middlewares : {
preSave : function ( ) {
// do something before the object is saved
} ,
} ,
} ) ;
中间件也可以是异步函数:
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [ 'firstName' ] ,
middlewares : {
preUpdateOne : async function {
// do something before the object is updated (asynchronous)
}
}
} ) ;
模糊搜索查询可以用作static
函数,也可以用作helper
,它可以让您将多个查询链接在一起。任何一种情况下的函数名称都是surprise、surprise、 fuzzySearch
。
实例方法最多可以接受三个参数。第一个是查询,它可以是String
或Object
。该参数是必需的。第二个参数可以是包含任何附加查询的Object
(例如age: { $gt: 18 }
),也可以是回调函数。如果第二个参数是查询,那么第三个参数是回调函数。如果不设置回调函数,结果将在 Promise 中返回。
下表包含第一个参数的预期键(如果是对象)
钥匙 | 类型 | 默认的 | 描述 |
---|---|---|---|
询问 | 细绳 | 无效的 | 要搜索的字符串 |
最小尺寸 | 整数 | 2 | N 克最小尺寸。 |
仅前缀 | 布尔值 | 错误的 | 只返回从单词开头开始的 ngram。 (它给出更精确的结果)前缀 |
精确的 | 布尔值 | 错误的 | 匹配短语,而不是单个术语 |
例子:
/* With string that returns a Promise */
User . fuzzySearch ( 'jo' ) . then ( console . log ) . catch ( console . error ) ;
/* With additional options that returns a Promise */
User . fuzzySearch ( { query : 'jo' , prefixOnly : true , minSize : 4 } )
. then ( console . log )
. catch ( console . error ) ;
/* With additional queries that returns a Promise */
User . fuzzySearch ( 'jo' , { age : { $gt : 18 } } )
. then ( console . log )
. catch ( console . error ) ;
/* With string and a callback */
User . fuzzySearch ( 'jo' , ( err , doc ) => {
if ( err ) {
console . error ( err ) ;
} else {
console . log ( doc ) ;
}
} ) ;
/* With additional queries and callback */
User . fuzzySearch ( 'jo' , { age : { $gt : 18 } } , ( err , doc ) => {
if ( err ) {
console . error ( err ) ;
} else {
console . log ( doc ) ;
}
} ) ;
您还可以使用查询辅助函数,它类似于实例方法,但用于猫鼬查询。查询帮助器方法允许您扩展 mongoose 的可链接查询构建器 API。
查询助手最多可接受两个参数。第一个是查询,它可以是String
或Object
。该参数是必需的。第二个参数可以是包含任何附加查询的Object
(例如, age: { $gt: 18 }
),这是可选的。此帮助程序不接受回调函数。如果你传递一个函数,它会抛出一个错误。有关查询助手的更多信息。
例子:
const user = await User . find ( { age : { $gte : 30 } } )
. fuzzySearch ( 'jo' )
. exec ( ) ;
该插件为所选字段创建索引。在下面的示例中,新索引将为firstName_fuzzy
和lastName_fuzzy
。此外,每个文档都将具有字段firstName_fuzzy
[String]和lastName_fuzzy
[String]。这些数组将包含所选字段的字谜。
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
age : Number ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
换句话说,当您创建或更新文档时,该插件会创建字谜词。所有预先存在的文档都不会包含这些模糊数组,因此fuzzySearch
函数将无法找到它们。
为了为预先存在的文档创建字谜词,您应该更新每个文档。下面的示例将firstName
属性更新到集合User
上的每个文档。
const cursor = Model . find ( ) . cursor ( ) ;
cursor . next ( function ( error , doc ) {
const obj = attrs . reduce ( ( acc , attr ) => ( { ... acc , [ attr ] : doc [ attr ] } ) , { } ) ;
return Model . findByIdAndUpdate ( doc . _id , obj ) ;
} ) ;
在前面的示例中,我们将firstName
和lastName
设置为模糊属性。如果从模糊字段中删除firstName
,则集合不会删除firstName_fuzzy
数组。如果要删除每个文档上的数组,则必须取消设置该值。
const cursor = Model . find ( ) . cursor ( ) ;
cursor . next ( function ( error , doc ) {
const $unset = attrs . reduce ( ( acc , attr ) => ( { ... acc , [ ` ${ attr } _fuzzy` ] : 1 } ) , { } ) ;
return Model . findByIdAndUpdate ( data . _id , { $unset } , { new : true , strict : false } ) ;
} ) ;
我们使用 jest 进行所有单元测试和集成测试。
$ npm test
注意:这将串行运行所有套件,以避免数据库上出现多个并发连接。
这将使用内存数据库运行测试。如果您出于某种原因希望在 mongo 实例上使用实际连接运行测试,请添加环境变量MONGO_DB
:
$ docker run --name mongo_fuzzy_test -p 27017:27017 -d mongo
$ MONGO_DB=true npm test
$ npm run test:unit
$ npm run test:integration
麻省理工学院许可证
版权所有 (c) 2019 瓦西利斯帕拉斯
特此免费授予获得本软件及相关文档文件(“软件”)副本的任何人不受限制地使用本软件,包括但不限于使用、复制、修改、合并的权利、发布、分发、再许可和/或销售软件的副本,并允许向其提供软件的人员这样做,但须满足以下条件:
上述版权声明和本许可声明应包含在本软件的所有副本或主要部分中。
本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有者均不对因本软件或本软件的使用或其他交易而引起的或与之相关的任何索赔、损害或其他责任负责,无论是合同、侵权还是其他行为。软件。