mongoose-fuzzy-searching est un plugin simple et léger qui permet une recherche floue dans les documents dans MongoDB. Ce code est basé sur cet article.
Installer en utilisant npm
$ npm i mongoose-fuzzy-searching
ou en utilisant du fil
$ yarn add mongoose-fuzzy-searching
Avant de commencer, pour bénéficier des meilleures pratiques et éviter tout problème, gérez correctement tous les avertissements de dépréciation.
Afin de laisser le plugin créer les index, vous devez définir useCreateIndex
sur true. L'exemple ci-dessous montre comment se connecter à la base de données.
const options = {
useNewUrlParser : true ,
useUnifiedTopology : true ,
useFindAndModify : false ,
useCreateIndex : true ,
} ;
mongoose . Promise = global . Promise ;
return mongoose . connect ( URL , options ) ;
Dans l'exemple ci-dessous, nous avons une collection User
et nous souhaitons effectuer une recherche floue dans firstName
et 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 ) ;
}
Les résultats sont triés par clé confidenceScore
. Vous pouvez remplacer cette option.
try {
const users = await User . fuzzySearch ( 'jo' ) . sort ( { age : - 1 } ) . exec ( ) ;
console . log ( users ) ;
} catch ( e ) {
console . error ( e ) ;
}
Les options peuvent contenir fields
et middlewares
.
L'attribut Fields est obligatoire et doit être soit un tableau de Strings
, soit un tableau d' Objects
.
Si vous souhaitez utiliser les options par défaut pour tous vos champs, vous pouvez simplement les transmettre sous forme de chaîne.
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' ] } ) ;
Si vous souhaitez remplacer l'une des options par défaut pour vos arguments, vous pouvez les ajouter en tant qu'objet et remplacer n'importe quelle valeur de votre choix. Le tableau ci-dessous contient les clés attendues pour cet objet.
clé | taper | défaut | description |
---|---|---|---|
nom | Chaîne | nul | Nom de la clé de collecte |
Taille min | Entier | 2 | Taille minimale de N-grammes. En savoir plus sur les N-grammes |
poids | Entier | 1 | Indique l'importance du champ par rapport aux autres champs indexés en termes de score de recherche de texte. En savoir plus sur les pondérations des indices |
préfixe uniquement | Booléen | FAUX | Renvoie uniquement les ngrammes à partir du début du mot. (Cela donne des résultats plus précis) |
escapeSpécialPersonnages | Booléen | vrai | Supprimez les caractères spéciaux des N-grammes. |
clés | Tableau[Chaîne] | nul | Si le type de l'attribut de collection est Object ou [Object] (voir exemple), vous pouvez définir quels attributs seront utilisés pour la recherche floue |
Exemple:
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' ] ,
} ,
] ,
} ) ;
Les middlewares sont un Object
facultatif qui peut contenir pre
-middlewares personnalisés. Ce plugin utilise ces middlewares afin de créer ou mettre à jour les éléments flous. Cela signifie que si vous ajoutez pre
middlewares, ils ne seront jamais appelés puisque le plugin les remplace. Pour éviter ce problème, vous pouvez transmettre vos middlewares personnalisés dans le plugin. Vos middlewares seront appelés en premier . Les middlewares que vous pouvez utiliser sont :
schema.pre("save", ...)
schema.pre("insertMany", ...)
schema.pre("update", ...)
schema.pre("updateOne", ...)
schema.pre("findOneAndUpdate", ...)
schema.pre("updateMany", ...)
Si vous souhaitez ajouter l'un des middlewares ci-dessus, vous pouvez l'ajouter directement sur le plugin.
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
} ,
} ,
} ) ;
Les middlewares peuvent également être des fonctions asynchrones :
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 requête de recherche floue peut être utilisée soit comme fonction static
, soit comme helper
, ce qui vous permet d'enchaîner plusieurs requêtes ensemble. Le nom de la fonction dans les deux cas est surprise, surprise, fuzzySearch
.
La méthode d’instance peut accepter jusqu’à trois paramètres. La première est la requête, qui peut être soit une String
, soit un Object
. Ce paramètre est obligatoire . Le deuxième paramètre peut être soit un Object
contenant des requêtes supplémentaires (par exemple age: { $gt: 18 }
), soit une fonction de rappel. Si le deuxième paramètre correspond aux requêtes, alors le troisième paramètre est la fonction de rappel. Si vous ne définissez pas de fonction de rappel, les résultats seront renvoyés dans une promesse.
Le tableau ci-dessous contient les clés attendues pour le premier paramètre (s'il s'agit d'un objet)
clé | taper | sourd | description |
---|---|---|---|
requête | Chaîne | nul | Chaîne à rechercher |
Taille min | Entier | 2 | Taille minimale de N-grammes. |
préfixe uniquement | Booléen | FAUX | Renvoie uniquement les ngrammes à partir du début du mot. (Cela donne des résultats plus précis) le préfixe |
exact | Booléen | FAUX | Correspond à une phrase, par opposition à des termes individuels |
Exemple:
/* 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 ) ;
}
} ) ;
Vous pouvez également utiliser la requête comme une fonction d'assistance, qui ressemble aux méthodes d'instance mais pour les requêtes mangouste. Les méthodes d'assistance aux requêtes vous permettent d'étendre l'API de création de requêtes chaînables de Mongoose.
L'assistant de requête peut accepter jusqu'à deux paramètres. La première est la requête, qui peut être soit une String
, soit un Object
. Ce paramètre est obligatoire . Le deuxième paramètre peut être un Object
contenant des requêtes supplémentaires (par exemple age: { $gt: 18 }
), ce qui est facultatif. Ces assistants n'acceptent pas de fonction de rappel. Si vous transmettez une fonction, une erreur sera générée. En savoir plus sur les assistants de requête.
Exemple:
const user = await User . find ( { age : { $gte : 30 } } )
. fuzzySearch ( 'jo' )
. exec ( ) ;
Le plugin crée des index pour les champs sélectionnés. Dans l'exemple ci-dessous, les nouveaux index seront firstName_fuzzy
et lastName_fuzzy
. De plus, chaque document aura les champs firstName_fuzzy
[String] et lastName_fuzzy
[String]. Ces tableaux contiendront les anagrammes des champs sélectionnés.
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 d’autres termes, ce plugin crée des anagrammes lorsque vous créez ou mettez à jour un document. Tous les documents préexistants ne contiendront pas ces tableaux flous, donc la fonction fuzzySearch
ne pourra pas les trouver.
Afin de créer des anagrammes pour des documents préexistants, vous devez mettre à jour chaque document. L'exemple ci-dessous met à jour l'attribut firstName
pour chaque document de la collection 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 ) ;
} ) ;
Dans l'exemple précédent, nous définissons firstName
et lastName
comme attributs flous. Si vous supprimez le firstName
des champs flous, le tableau firstName_fuzzy
ne sera pas supprimé par la collection. Si vous souhaitez supprimer le tableau de chaque document, vous devez supprimer cette valeur.
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 } ) ;
} ) ;
Nous utilisons Jest pour tous nos tests unitaires et d'intégration.
$ npm test
Remarque : cela exécutera toutes les suites en série pour éviter plusieurs connexions simultanées sur la base de données.
Cela exécutera les tests en utilisant une base de données mémoire. Si vous souhaitez pour une raison quelconque exécuter les tests en utilisant une connexion réelle sur une instance mongo, ajoutez la variable d'environnement 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
Licence MIT
Copyright (c) 2019 Vassilis Pallas
L'autorisation est accordée par la présente, gratuitement, à toute personne obtenant une copie de ce logiciel et des fichiers de documentation associés (le « Logiciel »), d'utiliser le Logiciel sans restriction, y compris, sans limitation, les droits d'utilisation, de copie, de modification, de fusion. , publier, distribuer, accorder des sous-licences et/ou vendre des copies du Logiciel, et permettre aux personnes à qui le Logiciel est fourni de le faire, sous réserve des conditions suivantes :
L'avis de droit d'auteur ci-dessus et cet avis d'autorisation doivent être inclus dans toutes les copies ou parties substantielles du logiciel.
LE LOGICIEL EST FOURNI « EN L'ÉTAT », SANS GARANTIE D'AUCUNE SORTE, EXPRESSE OU IMPLICITE, Y COMPRIS MAIS SANS LIMITATION LES GARANTIES DE QUALITÉ MARCHANDE, D'ADAPTATION À UN USAGE PARTICULIER ET DE NON-VIOLATION. EN AUCUN CAS LES AUTEURS OU LES TITULAIRES DES DROITS D'AUTEUR NE SERONT RESPONSABLES DE TOUTE RÉCLAMATION, DOMMAGES OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS UNE ACTION CONTRACTUELLE, DÉLIT OU AUTRE, DÉCOULANT DE, DE OU EN RELATION AVEC LE LOGICIEL OU L'UTILISATION OU D'AUTRES TRANSACTIONS DANS LE LOGICIEL.