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 | Обозначает значимость поля относительно других индексированных полей с точки зрения оценки текстового поиска. Подробнее о весах индексов… |
только префикс | логическое значение | ЛОЖЬ | Возвращайте только ngrams с начала слова. (Это дает более точные результаты) |
escapeSpecialCharacters | логическое значение | истинный | Удалить специальные символы из 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
, которая позволяет объединять несколько запросов в цепочку. Имя функции в любом случае — сюрприз, сюрприз, fuzzySearch
.
Метод экземпляра может принимать до трех параметров. Первый — это запрос, который может быть String
или Object
. Этот параметр является обязательным . Вторым параметром может быть либо Object
, содержащий дополнительные запросы (например age: { $gt: 18 }
), либо функция обратного вызова. Если второй параметр — это запросы, то третий параметр — это функция обратного вызова. Если вы не установите функцию обратного вызова, результаты будут возвращены внутри обещания.
В таблице ниже указаны ожидаемые ключи для первого параметра (если это объект).
ключ | тип | глухой | описание |
---|---|---|---|
запрос | Нить | нулевой | Строка для поиска |
минразмер | Целое число | 2 | Минимальный размер N-грамм. |
только префикс | логическое значение | ЛОЖЬ | Возвращайте ngrams только с начала слова. (Это дает более точные результаты) префикс |
точный | логическое значение | ЛОЖЬ | Совпадения по фразе, а не по отдельным терминам |
Пример:
/* 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-интерфейс построения цепочек запросов mongoose.
Помощник по запросам может принимать до двух параметров. Первый — это запрос, который может быть 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
Лицензия MIT
Copyright (c) 2019 Василис Паллас
Настоящим разрешение бесплатно предоставляется любому лицу, получившему копию этого программного обеспечения и связанных с ним файлов документации («Программное обеспечение»), на использование Программного обеспечения без ограничений, включая, помимо прочего, права на использование, копирование, изменение, объединение. публиковать, распространять, сублицензировать и/или продавать копии Программного обеспечения, а также разрешать лицам, которым предоставлено Программное обеспечение, делать это при соблюдении следующих условий:
Вышеупомянутое уведомление об авторских правах и данное уведомление о разрешении должны быть включены во все копии или существенные части Программного обеспечения.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЯМИ ТОВАРНОЙ ЦЕННОСТИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕНАРУШЕНИЯ ПРАВ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ ИЛИ ОБЛАДАТЕЛИ АВТОРСКИХ ПРАВ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГУЮ ОТВЕТСТВЕННОСТЬ, БУДЬ В ДЕЙСТВИЯХ ПО КОНТРАКТУ, ПРАВОНАРУШЕНИЮ ИЛИ ДРУГИМ ОБРАЗОМ, ВОЗНИКАЮЩИЕ ОТ, ИЗ ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ СДЕЛКАМИ, ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.