mongoose-fuzzy-searching es un complemento simple y liviano que permite la búsqueda difusa en documentos en MongoDB. Este código se basa en este artículo.
Instalar usando npm
$ npm i mongoose-fuzzy-searching
o usando hilo
$ yarn add mongoose-fuzzy-searching
Antes de comenzar, para conocer las mejores prácticas y evitar problemas, maneje correctamente todas las advertencias de obsolescencia.
Para permitir que el complemento cree los índices, debe configurar useCreateIndex
en verdadero. El siguiente ejemplo demuestra cómo conectarse con la base de datos.
const options = {
useNewUrlParser : true ,
useUnifiedTopology : true ,
useFindAndModify : false ,
useCreateIndex : true ,
} ;
mongoose . Promise = global . Promise ;
return mongoose . connect ( URL , options ) ;
En el siguiente ejemplo, tenemos una colección User
y queremos realizar una búsqueda difusa en firstName
y 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 ) ;
}
Los resultados se ordenan por la clave confidenceScore
. Puede anular esta opción.
try {
const users = await User . fuzzySearch ( 'jo' ) . sort ( { age : - 1 } ) . exec ( ) ;
console . log ( users ) ;
} catch ( e ) {
console . error ( e ) ;
}
Las opciones pueden contener fields
y middlewares
.
El atributo Fields es obligatorio y debe ser una matriz de Strings
o una matriz de Objects
.
Si desea utilizar las opciones predeterminadas para todos sus campos, puede simplemente pasarlas como una cadena.
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' ] } ) ;
En caso de que desee anular alguna de las opciones predeterminadas para sus argumentos, puede agregarlas como un objeto y anular cualquiera de los valores que desee. La siguiente tabla contiene las claves esperadas para este objeto.
llave | tipo | por defecto | descripción |
---|---|---|---|
nombre | Cadena | nulo | Nombre de la clave de colección |
tamaño mínimo | Entero | 2 | Tamaño mínimo de N gramos. Más información sobre N-gramas |
peso | Entero | 1 | Denota la importancia del campo en relación con los otros campos indexados en términos de puntuación de búsqueda de texto. Obtenga más información sobre las ponderaciones de los índices |
solo prefijo | booleano | FALSO | Solo devuelve ngramas desde el inicio de la palabra. (Da resultados más precisos) |
escaparPersonajes especiales | booleano | verdadero | Elimina caracteres especiales de N-gramas. |
llaves | Matriz[Cadena] | nulo | Si el tipo de atributo de la colección es Object u [Object] (ver ejemplo), puede definir qué atributos se utilizarán para la búsqueda difusa |
Ejemplo:
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' ] ,
} ,
] ,
} ) ;
Middlewares es un Object
opcional que puede contener pre
-middlewares personalizados. Este complemento utiliza estos middlewares para crear o actualizar los elementos difusos. Eso significa que si agrega middlewares pre
, nunca serán llamados ya que el complemento los anula. Para evitar ese problema, puede pasar sus midlewares personalizados al complemento. Sus middlewares serán llamados primero . Los middlewares que puedes pasar son:
schema.pre("save", ...)
schema.pre("insertMany", ...)
schema.pre("update", ...)
schema.pre("updateOne", ...)
schema.pre("findOneAndUpdate", ...)
schema.pre("updateMany", ...)
Si desea agregar alguno de los middlewares anteriores, puede agregarlo directamente en el complemento.
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
} ,
} ,
} ) ;
Los middlewares también pueden ser funciones asincrónicas:
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)
}
}
} ) ;
La consulta de búsqueda difusa se puede utilizar como función static
o como helper
, que le permite encadenar varias consultas. El nombre de la función en cualquier caso es sorpresa, sorpresa, fuzzySearch
.
El método de instancia puede aceptar hasta tres parámetros. La primera es la consulta, que puede ser una String
o un Object
. Este parámetro es obligatorio . El segundo parámetro puede ser un Object
que contenga consultas adicionales (por ejemplo age: { $gt: 18 }
) o una función de devolución de llamada. Si el segundo parámetro son las consultas, entonces el tercer parámetro es la función de devolución de llamada. Si no configura una función de devolución de llamada, los resultados se devolverán dentro de una Promesa.
La siguiente tabla contiene las claves esperadas para el primer parámetro (si es un objeto)
llave | tipo | sordo | descripción |
---|---|---|---|
consulta | Cadena | nulo | Cadena para buscar |
tamaño mínimo | Entero | 2 | Tamaño mínimo de N gramos. |
solo prefijo | booleano | FALSO | Solo devuelve ngramas desde el inicio de la palabra. (Da resultados más precisos) el prefijo |
exacto | booleano | FALSO | Coincidencias en una frase, a diferencia de términos individuales |
Ejemplo:
/* 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 ) ;
}
} ) ;
También puede utilizar la consulta como función auxiliar, que es como métodos de instancia pero para consultas de mangosta. Los métodos de ayuda de consulta le permiten ampliar la API del generador de consultas encadenables de Mongoose.
El asistente de consulta puede aceptar hasta dos parámetros. La primera es la consulta, que puede ser una String
o un Object
. Este parámetro es obligatorio . El segundo parámetro puede ser un Object
que contenga consultas adicionales (por ejemplo, age: { $gt: 18 }
), que es opcional. Estos ayudantes no aceptan una función de devolución de llamada. Si pasa una función, arrojará un error. Más información sobre los asistentes de consulta.
Ejemplo:
const user = await User . find ( { age : { $gte : 30 } } )
. fuzzySearch ( 'jo' )
. exec ( ) ;
El complemento crea índices para los campos seleccionados. En el siguiente ejemplo, los nuevos índices serán firstName_fuzzy
y lastName_fuzzy
. Además, cada documento tendrá los campos firstName_fuzzy
[String] y lastName_fuzzy
[String]. Estas matrices contendrán los anagramas de los campos seleccionados.
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' ] } ) ;
En otras palabras, este complemento crea anagramas cuando crea o actualiza un documento. Todos los documentos preexistentes no contendrán estas matrices difusas, por lo que la función fuzzySearch
no podrá encontrarlas.
Para crear anagramas para documentos preexistentes, debe actualizar cada documento. El siguiente ejemplo actualiza el atributo firstName
de cada documento de la colección 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 ) ;
} ) ;
En el ejemplo anterior, configuramos firstName
y lastName
como atributos difusos. Si elimina el firstName
de los campos difusos, la colección no eliminará la matriz firstName_fuzzy
. Si desea eliminar la matriz en cada documento, debe desarmar ese valor.
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 } ) ;
} ) ;
Usamos jest para todas nuestras pruebas unitarias y de integración.
$ npm test
Nota: esto ejecutará todas las suites en serie para evitar múltiples conexiones simultáneas en la base de datos.
Esto ejecutará las pruebas utilizando una base de datos de memoria. Si por algún motivo desea ejecutar las pruebas utilizando una conexión real en una instancia de mongo, agregue la variable de entorno 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
Licencia MIT
Copyright (c) 2019 Vassilis Pallas
Por el presente se otorga permiso, sin cargo, a cualquier persona que obtenga una copia de este software y los archivos de documentación asociados (el "Software"), para operar con el Software sin restricciones, incluidos, entre otros, los derechos de uso, copia, modificación, fusión. , publicar, distribuir, sublicenciar y/o vender copias del Software, y permitir que las personas a quienes se les proporciona el Software lo hagan, sujeto a las siguientes condiciones:
El aviso de derechos de autor anterior y este aviso de permiso se incluirán en todas las copias o partes sustanciales del Software.
EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O IMPLÍCITA, INCLUYENDO PERO NO LIMITADO A LAS GARANTÍAS DE COMERCIABILIDAD, IDONEIDAD PARA UN PROPÓSITO PARTICULAR Y NO INFRACCIÓN. EN NINGÚN CASO LOS AUTORES O TITULARES DE DERECHOS DE AUTOR SERÁN RESPONSABLES DE NINGÚN RECLAMO, DAÑO U OTRA RESPONSABILIDAD, YA SEA EN UNA ACCIÓN CONTRACTUAL, AGRAVIO O DE OTRA MANERA, QUE SURJA DE, FUERA DE O EN RELACIÓN CON EL SOFTWARE O EL USO U OTRAS NEGOCIOS EN EL SOFTWARE.