Giter VIP home page Giter VIP logo

mongoose-fuzzy-searching's People

Contributors

aladinflux avatar bswank avatar dbads avatar dependabot[bot] avatar fossabot avatar hommesauvage avatar molteh avatar pong420 avatar vassilispallas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mongoose-fuzzy-searching's Issues

Using keys with dynamic object values, does not set fuzzy values

Hi,

I am using another mongoose plugin for multiple languages, so it dynamically creates new field in the name field.
https://www.npmjs.com/package/mongoose-intl plugin for multiple languages

const itemSchema = new Schema({
  name: {
    type: String,
    required: true,
    intl: true,
  },
  description: {
    type: String,
    intl: true,
  },
  base_price: {
    type: Number,
    required: true,
  },
})

itemSchema.plugin(mongooseIntl, { languages: LANGUAGES.split(','), defaultLanguage: 'en' });
itemSchema.plugin(mongoose_fuzzy_searching, 
  { fields: [
    {
      name: 'name',
      keys: LANGUAGES.split(',')
    },
  ]});
const itemModel = mongoose.model('item', itemSchema);

But when i try to create a new document with the name field as object, i get a document with name_fuzzy as an array and all the languages as array elements but all of them are empty.

{
  "name": {
    "en": "Tandoori Maggie",
    "ja": "DMTC"
  },
  "base_price": 123,
  "description": {
    "en": "some test desc",
    "ja": "new testing"
  },
}

same for description field

output:

[{
  "_id": {
    "$oid": "5f46b99ead705f1afcc5e74a"
  },
  "name": {
    "en": "Tandoori Maggie",
    "ja": "DMTC"
  }
  "name_fuzzy": [
    {
      "en_fuzzy": [],
      "ja_fuzzy": [],
      "et_fuzzy": [],
      "ru_fuzzy": [],
      "es_fuzzy": [],
      "de_fuzzy": [],
      "th_fuzzy": [],
      "ms_fuzzy": [],
      "zh_fuzzy": [],
      "fil_fuzzy": []
    }
  ],
  "createdAt": {
    "$date": "2020-08-26T19:35:58.892Z"
  },
  "updatedAt": {
    "$date": "2020-08-26T19:35:58.892Z"
  }
}]

Thanks

Getting MongoServerError: language override unsupported when plugin is used in a collection with the field language with invalid values

Do you want to request a feature, an issue, or report a bug?
bug

What is the current behaviour?
I know this repository seems like is no longer maintained, I had to fork this to fix the issue but just in case it gets picked up again.

The plugin always sets the "language override" to its default value of language. This is an issue when the collection
documents already have the language field with values not compatible with MongoDB or are expected to be used in another way different from what the index intends to use it for. This can either make the creation of the index to fail or throw an error when trying to save a document with a non-valid value.

In my case, I have a collection where I store the preferred language of a user in the field language, the plugin is not compatible since I have documents whose language value is en-US

If the current behaviour is a bug, please provide the steps to reproduce.

const mongoose = require('mongoose')
const fuzzySearchPlugin = require('mongoose-fuzzy-searching')

const schema = new Schema({
  name: { type: String },
  language: { type: String },
}, { collection: 'User' })


schema.plugin(fuzzySearchPlugin, {
  fields: [{
    name: 'name',
    minSize: 3,
    weight: 3,
    prefixOnly: true,
  }],
})

const User = model('User', schema)

const myUser = new User({ name: 'John', language: 'en-US' })
myUser.save() // this promise will be rejected with `MongoServerError: language override unsupported: en-US`

What is the expected behaviour?
Allow the plugin to accept the override_language option for cases like this where changing the name of a field in a collection is not feasible, something like

schema.plugin(fuzzySearchPlugin, {
  fields: [{
    name: 'name',
    minSize: 3,
    weight: 3,
    prefixOnly: true,
  }],
language_override: 'document_language',
})

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.

Cannot find some string values

--When I search for 'ano' I get this:
Mongoose: tasks.find({ '$text': { '$search': 'no an ano' } }, { projection: {} })
Mongoose: tasks.find({ '$text': { '$search': 'no an ano' } }, { projection: {} })
search Yet Another Completely unrelated name +0ms
search Another Completely unrelated name +0ms

--With 'another, I get these hits:

Mongoose: tasks.find({ '$text': { '$search': 'er he th ot no an her the oth not ano ther othe noth anot other nothe anoth nother anothe another' } }, { projection: {} })
Mongoose: tasks.find({ '$text': { '$search': 'er he th ot no an her the oth not ano ther othe noth anot other nothe anoth nother anothe another' } }, { projection: {} })
search Yet Another Completely unrelated name +0ms
search Another Completely unrelated name +0ms

--Searching for 'ye', I get hits:
Mongoose: tasks.find({ '$text': { '$search': 'ye' } }, { projection: {} })
Mongoose: tasks.find({ '$text': { '$search': 'ye' } }, { projection: {} })
search Yet Another Completely unrelated name +0ms

--Searching for 'an', I don't get any hits:

--But when I search 'an' I do not get any hit:
Mongoose: tasks.find({ '$text': { '$search': 'an' } }, { projection: {} })
Mongoose: tasks.find({ '$text': { '$search': 'an' } }, { projection: {} })

How come 'an' is not found and yet 'ye' was found?

Not using fuzzySearch() seemed to work, I can get hits for 'an'

const queryOverride = {
'$or':
[
{'info_fuzzy.name1_fuzzy': {'$regex': ^${searchValue}}},
{'info_fuzzy.title_fuzzy': {'$regex': ^${searchValue}}},
{'info_fuzzy.version_fuzzy': {'$regex': ^${searchValue}}},
{'info_fuzzy.description_fuzzy': {'$regex': ^${searchValue}}}
]
}
const results = await Task
.find(queryOverride)
// .fuzzySearch(searchValue)
.exec();

Mongoose: tasks.find({ '$or': [ { 'info_fuzzy.name1_fuzzy': { '$regex': '^an' } }, { 'info_fuzzy.title_fuzzy': { '$regex': '^an' } }, { 'info_fuzzy.version_fuzzy': { '$regex': '^an' } }, { 'info_fuzzy.description_fuzzy': { '$regex': '^an' } } ] }, { projection: {} })
Mongoose: tasks.createIndex({ 'info_fuzzy.name1_fuzzy': 'text', 'info_fuzzy.title_fuzzy': 'text', 'info_fuzzy.version_fuzzy': 'text', 'info_fuzzy.description_fuzzy': 'text' }, { weights: {}, name: 'fuzzy_text', background: true })
search Army of Ants +0ms
search Army Ants +0ms
search Ant Man +0ms
search Another Completely unrelated name +0ms
search Yet Another Completely unrelated name +1ms


Heres my schema:

const mongoose = require('mongoose');
const mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');

const taskSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
environment: {
type: String,
required: true
},
info: {
name1: String,
title: String,
version: String,
description: String
},
completed: {
type: Boolean,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}, {
timestamps: true
});

// NOTE: Index need to be dropped and re-created each time fields are updated
taskSchema.plugin( mongoose_fuzzy_searching, {
fields: [
// {
// name: 'name',
// minSize: 1,
// prefixOnly: false,
// },
{
name: 'info',
minSize: 2,
prefixOnly: false,
keys: [
'name1',
'title',
'version',
'description'
]
}
]
}
);

module.exports = mongoose.model('Task', taskSchema);

Fuzzy Search not working if query is provided

Do you want to request a feature, an issue, or report a bug?
Yes

What is the current behaviour?
If passed something to the query no document is returned, if nothing is passed to the query every post is correctly returned.
Even if the full entry content is provided no document is found

Edit:
I found out that the indexes are appended with _fuzzy, removing them results in correct behaviour but the fields provided for index are removed from the documents found

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
Returning a document using fuzzy search

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.

"mongoose": "^6.2.10",
"mongoose-fuzzy-searching": "^2.0.2",

unaccurate search

Hello, I'm was looking for a fuzzy search before learning elasticsearch/lucene and then I found your plugin. But I'm having some really unaccurate results
Here is what I got for fuzzy fields:
fields: [{
name: 'name',
minSize: 3,
weight: 10,
}
}]
(I did it like that just to try you plugin)

But with the plainText "mart" I'm getting items with field "name" that doesn't contain "mart" or similar (e.g : "Ceinture Noire de Frank Lee Bruce"), but it contains "mart" in other fields (e.g: description: "Célèbre combattant du dimanche, Frank s'est reconverti dans les arts martiaux après avoir lamentablement raté son diplôme de tailleur de pierres.")

So I tried to add the field description like that :
{
name: 'description',
minSize: 10,
weight: 0
}
But "mart" is still returning the same data.

In my data i'm having a LOT of items with "marteau ...."

Am I doing something bad ? Did I missed something ?

Thanks a lot

Pre-save hook removed, still can't find any user

Works perfectly with other collections, _fuzzy fields are all created

const userSchema = new mongoose.Schema({
    createdAt: { type: Date, default: new Date() },
    email: { type: String, required: true, unique: true },
    emailConfirmed: { type: Boolean, default: false },
    emailToken: { type: String, default: crypto.randomBytes(16).toString('hex')},
    password: {type: String, required: true},
    passwordResetToken: String,
    passwordResetExpires: Date,


    firstName: {type: String, required: true},
    lastName: String,

}, { timestamps: true });

/*
/**
 * Password hash middleware.
 */
/*
userSchema.pre("save", function (next) {
    const user = this as IUser;
    bcrypt.hash(user.password, 10, (err, hash) => {
        user.password = hash;
        next();
    });
});

userSchema.pre("update", function (next) {
    const modifiedPassword = this.getUpdate().$set.password;

    if (!modifiedPassword)
        return next();

    try {
        bcrypt.hash(modifiedPassword, 10, (err, hash) => {
            this.getUpdate().$set.password = hash;
            next();
        });
    } catch (error) {
        return next(error);
    }
});
*/

userSchema.methods.comparePassword = function (candidatePassword: string): Promise<boolean> {
    let password = this.password;
    return new Promise((resolve, reject) => {
        bcrypt.compare(candidatePassword, password, (err, success) => {
            if (err) return reject(err);
            return resolve(success);
        });
    });
};

userSchema.plugin(mongoose_fuzzy_searching, {fields: [
        {
            name: 'firstName',
            weight: 10,
        },
        {
            name: 'lastName',
            weight: 5,
        },
    ]
});

export const User = mongoose.model<IUser>("User", userSchema);

export default User;

Access confidence score

The confidence score for some reason isnt accessible from the array of objects it returns.
my code:

  await Card.fuzzySearch({ query: req.params.name, limit: 10 })
    .then(card => {
      for (let i = 0; i < card.length; i++) {
        console.log(card[i].confidenceScore);
      }
      cards = card;
    });

Search not working with object data

Do you want to request a feature, an issue, or report a bug?
Yes

What is the current behaviour?
Can't search with index and object data

If the current behaviour is a bug, please provide the steps to reproduce.
I create user Schema with fuzzy search plugin as below

const UserSchema = new Schema({
  name: {
    firstName: String,
    lastName: String
  },
  email: String
},{timestamps: true});
UserSchema.index({"$**": "text"});
UserSchema.plugin(mongoose_fuzzy_searching, { fields: ['name.firstName', 'name.lastName', 'email'] });
const User = mongoose.model('User', UserSchema);

When try to search with firstname or last name it's return no results while already have results
User.fuzzySearch({query: 'jo'}).sort({ age: -1 }).exec();
Also check in mongoose database email_fuzzy have data but firstName_fuzzy haven't data

What is the expected behaviour?
Return results when add data as new User({ email : "[email protected]",name : {firstName: 'John A', lastName: 'Deo'}});
If this is a feature request, what is the motivation or use case for changing
the behaviour?

No
Please mention other relevant information such as Node.js and mongoose version.
Node : 16.6.2
Mongoose : 5.10.19

update to mongoose 6.x.x

Do you want to request a feature, an issue, or report a bug?
yes
What is the current behaviour?
I can't install it with mongoose 6.x.x normally.
If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
It should have mongoose 6.x.x included in peer dependency
If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.
node js 16.13.0
mongoose 6.0.12

toJSON and toObject transform do not work any more

This two lines overrides transform method declared on schema level:

https://github.com/VassilisPallas/mongoose-fuzzy-searching/blob/master/index.js#L331

So, after adding this plugin it's impossible to use your own transformations.

const projectSchema = mongoose.Schema({
  _id: {
    type: ShortId, len: 5, base: 62, retries: 4,
  },
  name: {
    type: String,
    maxlength: 255,
  },
}, {
  timestamps: true,
  versionKey: false,
  toJSON: {
    virtuals: true,
    transform(doc, ret) {
      console.log('>>>> toJSON transform will never calls')
      return ret
    },
  },
  toObject: {
    virtuals: true,
    transform(doc, ret) {
      console.log('>>>>> toObject transform will never calls')
      return ret
    },
  },
})

Retroactive Adding Ngrams to Documents

I am adding the plugin to an existing mongo database. Is there a recommended way to update all pre-existing documents with ngrams (ie "userName_fuzzy")?

This would be great to addition to the readme.

Thank you!

Updating Fields to Empty String

Do you want to request a feature, an issue, or report a bug?
Bug

What is the current behaviour?
Updating a document's fuzzy search field (string) with a new value updates its associated fuzzy array (field _fuzzy). Updating the document's field a second time with an empty string does not update the associated fuzzy array.

If the current behaviour is a bug, please provide the steps to reproduce.

  1. Create a schema with a single string field
  2. Add that field as a mongoose fuzzy searching field
  3. Create a new object with that field as some string that is not empty and insert into database
  4. Update the documents field to be empty
  5. Check the value of the fields associated field _fuzzy array in the database
const mongoose = require("mongoose");
const fuzzy = require("mongoose-fuzzy-searching");

const options = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
  useCreateIndex: true,
};

mongoose.Promise = global.Promise;
mongoose.connect("URL");

const CommentSchema = new mongoose.Schema({ comment: String });
CommentSchema.plugin(fuzzy, { fields: ["comment"] });

const Comment = mongoose.model("Comment", CommentSchema);
module.exports = { Comment };

const comment = new Comment({ comment: "Test" });
try {
  comment.save();

  // Using timeouts in order to view documents in between updates
  setTimeout(() => {
    console.log("updating to empty...");
    comment.comment = "";
    comment.save();
  }, 3000);

  setTimeout(() => {
    console.log('updating to "NEW"...');
    comment.comment = "NEW";
    comment.save();
  }, 6000);
} catch (e) {
  console.log(e);
}

Initial Document

{
    "_id" : ObjectId("5fc7e091081cba2e17c6a849"),
    "comment_fuzzy" : [ 
        "st", 
        "es", 
        "te", 
        "est", 
        "tes", 
        "test"
    ],
    "comment" : "Test",
    "__v" : 0
}

Empty Update

{
    "_id" : ObjectId("5fc7e091081cba2e17c6a849"),
    "comment_fuzzy" : [ 
        "st", 
        "es", 
        "te", 
        "est", 
        "tes", 
        "test"
    ],
    "comment" : "",
    "__v" : 0
}

Final Update

{
    "_id" : ObjectId("5fc7e091081cba2e17c6a849"),
    "comment_fuzzy" : [ 
        "ew", 
        "ne", 
        "new"
    ],
    "comment" : "NEW",
    "__v" : 1
}

What is the expected behaviour?
The field _fuzzy array updates to empty when it's associated field is set to an empty string.

Please mention other relevant information such as Node.js and mongoose version.
Mongoose Fuzzy Searching v2.0.2
Mongoose v5.11.1
Node v12.20.0

Return 'matched word' metadata with search results

It would be great if, after a fuzzy search is performed, some metadata is returned about what word was used to match.

(The confidenceScore is returned, which is helpful, but it would be great if the search response also included the nGram / word with highest similarity to the input text).

Exact match result is not the first item returned

Do you want to request a feature, an issue, or report a bug?
Issue

What is the current behaviour?
Exact match result is not the first item returned

If the current behaviour is a bug, please provide the steps to reproduce.
This is the returned array for the query=lille with City.fuzzySearch(query).limit(5).exec() :

[
  { "nom": "Lillers",      "confidenceScore": 4.300000000000001 },
  { "nom": "Lillemer",     "confidenceScore": 4.300000000000001 },
  { "nom": "Lille",        "confidenceScore": 4.300000000000001 },
  { "nom": "Lillebonne",   "confidenceScore": 4.300000000000001 },
  { "nom": "Ille-sur-Têt", "confidenceScore": 4.2               }
]

What is the expected behaviour?
Exact match "Lille" should have a higher confidenceScore than the others

I'm using this function to bring the exact match up :

for (let i=0; i<answer.length; i++) {
    if (answer[i].nom.toLowerCase() === query) {
        answer.unshift(answer[i]);
        answer.splice(i+1,1);
    }
}

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.
node v14.4.0
mongoose 5.11.15

No output except Query object

Hello,
So I have an issue that I can’t seem to track down.
Using your simple implementation: If I use promises, I get nothing. If I assign Model.fuzzySearch(…) to a variable and console.log the variable, I get a Query object that contains schema…collection name...search anagram etc.
Below is the bit of code that spits out the Query object. A gist of the output is here

const mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');
const mongoose = require('mongoose')
const { Schema } = mongoose

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);

const user = new User({ firstName: 'Joseph', lastName: 'Doe', email: '[email protected]', age: 30 });

try {
  user.save();
  const users = User.fuzzySearch('joe');
  console.log(users);

} catch (e) {
  console.error(e);
}

I tried an implementation on my atlas db-collection and got the same result.
I’m not sure if I’m overlooking a dependency (I never got any errors), or if there’s an issue with the versions of node, mongoose. I'm not sure how to go about debugging this issue.
Software versions of pertinence:
mongoose: 5.9.20
mongodb: 3.5.9
node: 14.4.0
mongoose-fuzzy-searching: 1.3.1

Add option to use $all filter instead of $text search

Do you want to request a feature, an issue, or report a bug?
feature

What is the current behaviour?
Current behavior is to use $text query to search the collection. This gives inaccurate results because of lots of partial matches when searching multiple small common phrases.
Eg. when searching "prime bank" it is currently giving results which have only one of these at the top instead of the document which has both.

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
An option where only results are returned which contain all phrases searched. I was thinking how to do this, and instead of using $text search if I instead search the fuzzy array with {$all : } it gives better results.

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Limiting results when larger search query.

Please mention other relevant information such as Node.js and mongoose version.
Node: 14
Mongoose: 5.10

Fuzzy search same model, but different fields

Hi.

I have and model named Article that contains the tilte and content .

let mongoose = require('mongoose');
let Schema = mongoose.Schema;  
var mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');

var ArticleSchema = new Schema({
    title: {
        type: String,
    },
   content: {
        type: String,
    },
})

module.exports = mongoose.model('Article', ArticleSchema);

The model is exported and used in another .js.
How can I fuzzy search the title and content separately, without declaring

ArticleSchema.plugin(mongoose_fuzzy_searching, {fields: ['title', 'content']});

in the model schema file?

I want to have 2 functions that search articles one by the title, and the other one by the content, separately.

If I put the

ArticleSchema.plugin(mongoose_fuzzy_searching, {fields: ['title', 'content']});

then my both functions will use title and content for the fuzzy search.

Can I achieve something like this?

function a() {
    ArticleSchema.plugin(mongoose_fuzzy_searching, {fields: ['title']});
    fuzzySearch();
}
function b() {
    ArticleSchema.plugin(mongoose_fuzzy_searching, {fields: ['content']});
    fuzzySearch();
}

Working with unique values

Do you want to request a feature, an issue, or report a bug?
A feature I guess.
What is the current behaviour?

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
A way to filters the result by unique value. For examples, I got multiple documents with a "name" value. If I got multiple documents with same name, filtering them to get only one.
I know I can use distinct, but distinct is filtering, but returning only the fields you requested.

If this is a feature request, what is the motivation or use case for changing
the behaviour?

I actually need for filtering my +35 000 movies db where there is some duplicates, and I need to keep them in db, but I need for search to avoid duplicates. Thank you !
Please mention other relevant information such as Node.js and mongoose version.

TypeError: obj.fromObjectKeys is not a function

const mongoose = require('mongoose');
const mongooseFuzzySearching = require('mongoose-fuzzy-searching');
const updateFuzzy = require('../lib/updateModel');

/* const mongoosastic = require('mongoosastic');
const esClient = require('../searchConnection'); */

const RecipeSchema = mongoose.Schema({
title: {
type: String,
required: true,
},
category: {
type: mongoose.ObjectId,
ref: 'RecipeCategory',
},
tags: [{
family: {
type: String,
required: true,
},
title: {
type: String,
},
}],
previewImg: {
type: String,
required: true,
},
likes: {
type: Number,
default: 0,
},
time: {
type: Number,
default: 0,
},
portions: {
type: Number,
default: 1,
},
comments: [{
type: mongoose.ObjectId,
ref: 'Comment',
}],
products: [{
product: {
type: mongoose.ObjectId,
ref: 'Product',
},
value: {
type: Number,
default: 0,
},
valueType: { // 'volume', 'weight', 'count'
type: String,
default: 'count',
},
measureObj: {
measuringInstrument: {
type: mongoose.ObjectId,
ref: 'MeasuringInstrument',
},
count: {
type: Number,
default: 0,
},
},
}],
steps: [{
source: {
type: String,
},
type: {
type: String,
},
start: {
type: String,
},
end: {
type: String,
},
text: {
type: String,
required: true,
},
}],
active: {
type: Boolean,
default: true,
},
});

RecipeSchema.plugin(mongooseFuzzySearching, {
fields: [{
name: 'title',
minSize: 5,
},
{
name: 'tags',
keys: ['title'],
},
],
});

Getting the error "TypeError: obj.fromObjectKeys is not a function" when adding some objects or trying to work with pre-existing data or tryng to search something
Though, fuzzy objects are created o_O

No Error, no Results when setting other searchfields

Hey,
this seems to be more of an implementation problem but anyway:
Using your example code works fine, but when i change the searching-fields to something other than "firstName" or "lastName" i dont get any results and no error.

var mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');
const mongoose = require("mongoose");

var UserSchema = new mongoose.Schema({
    firstName: String,
    lastName: String,
    email: String,
    age: Number,
    jobName: String
});

UserSchema.plugin(mongoose_fuzzy_searching, {fields: ['jobName']});

var User = mongoose.model('fuzUser', UserSchema);

async function testFuzzy(){

    var user = new User({ firstName: 'Joe',  lastName: 'Doe', email: '[email protected]', age: 30, jobName:'carpenter'});
         await user.save(function () {console.log("saved") });
         await User.fuzzySearch('carpenter', function (err, users) {
            console.error(err);
            console.log("users: ", users);
       })
   
}
 testFuzzy();

Output is:

saved
null
users: []

Do you have any idea where my error is ?

Specify an array field of strings

My document has an array field of strings that will be used as keywords or tags, currently this will trhow the error text.split is not a function, my quick fix was to check if text is an array and join the elements:

 if (Array.isArray(text)) {
    if (text.length === 0) {
        return [];
    }
    text = text.join(' ');
}

TypeScript support?

Do you want to request a feature, an issue, or report a bug?
Feature-ish

What is the current behaviour?
No TypeScript typings.

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
To have TypeScript support for type checks and IDE auto-completion.

If this is a feature request, what is the motivation or use case for changing
the behaviour?

TypeScript is widely popular and most packages support it either separately through the @types organization or by including a typings.d.ts file inside the package itself.

Please mention other relevant information such as Node.js and mongoose version.
Node: 12.13.1
Mongoose: 5.9.25

Provide query helper instead of static method

Do you want to request a feature, an issue, or report a bug?

Feature

What is the current behaviour?

If the current behaviour is a bug, please provide the steps to reproduce.

Currently fuzzySearch is only available through the Model static function. But if I have a function that returns me a Query instance then I am not able to add fuzzy search constraints to that query.

What is the expected behaviour?

Use the official recommended way of registering a query helper instead of adding statics, https://mongoosejs.com/docs/guide.html#query-helpers

If this is a feature request, what is the motivation or use case for changing
the behaviour?

This would allow using fuzzySearch functionality while dynamically creating queries.

Please mention other relevant information such as Node.js and mongoose version.
Node: 10.16
Mongoose: 5.9.14

how to show some related data if no data found?

Do you want to request a feature, an issue, or report a bug?
Yes
What is the current behaviour?
If the query doesn't match, it gives no output.
If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
Can we have a filter like if no result fount then send some other results where query at least matches with the few letters of the data
If this is a feature request, what is the motivation or use case for changing
the behaviour?

it sends empty array if not result found
Please mention other relevant information such as Node.js and mongoose version.
Node 16.8.0
mongoose 6.0.5

"Key" param in options object only works with object arrays

The document that I am to query has a structure similar to this one:

var BookSchema = new Schema({
    iban: String,
    author: String,
    publisher: String
    name: {
          en: String,
          fi: String,
          sv: String
     }
});

Now, I would like to perform a fuzzy search using as fields name.en, name.fi, name.sv

The documentation states the following about using key into fields array of objects:

If the type of the collection attribute is Object, you can define which attributes will be used for fuzzy searching

Thus I, specified the fields object on which to build the n-grams like this:

BookSchema.plugin(mongoose_fuzzy_searching, {
    fields: [{
            name: 'name',
            keys: ["en", "fi", "sv"]
        }]   
});

This leads to errors during document insertion because the objectKeysCb expects to find an array of objects rather than a single one and the forEach method is not defined.

Also, the example provided uses an array of objects instead of an object as stated in the cited documentation. I think this case should be also handled by the function.

If you agree I will open a pull request and push a fix to this issue.

How to handle nested field? The Anagram is not created under info.name1

My model looks like this:

const taskSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  info: {
    name1: String,
    title: String,
    version: String,
    description: String
  },
  completed: {
    type: Boolean,
    required: true
  },
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'
  }
}, {
    timestamps: true
});

taskSchema.plugin( mongoose_fuzzy_searching, {
    fields: [{
        name: 'info.name1',
        minSize: 2,
        prefixOnly: false,
    }]
    }
);

I saved :

 const debug = require('debug')('add_new_task');
    const input = {
        name: taskTitle,
        info: {
            name1: "Army Ants1",
            title: "Army Ants2",
            version: "Army Ants3",
            description: "Army Ants4"
        },
        completed: false
    };
    try {
        const user = await User.findOne({email: taskEmail});
        debug(`user ${JSON.stringify(user, null,2)}`);
        const task = new Task({...input, user: user.id});
        const result = await task.save();
        user.tasks.push(result.id);
        await user.save();
        debug(`result=${JSON.stringify(result, null,2)}`);
        return result;
    } catch (error) {
        console.log(error);
    }

The Anagram is not created under info.name1:

add_new_task result={
add_new_task "info": {
add_new_task "name1_fuzzy": [
add_new_task ""
add_new_task ],
add_new_task "name1": "Army Ants1",
add_new_task "title": "Army Ants2",
add_new_task "version": "Army Ants3",
add_new_task "description": "Army Ants4"
add_new_task },
add_new_task "_id": "5fb3130d6d087b31b974acff",
add_new_task "name": "Army of Ants",
add_new_task "completed": false,
add_new_task "user": "5f91caa051fa0512993e9326",
add_new_task "createdAt": "2020-11-17T00:02:22.006Z",
add_new_task "updatedAt": "2020-11-17T00:02:22.006Z",
add_new_task "__v": 0
add_new_task } +167ms

name1_fuzzy is empty.

Not working with other plugins

Hi, thank you for the great plugin.
Found a issue tough.
Iam trying to use it with another plugin(mongoose-paginate) and had no luck yet...
Here's my router's code

// -Get all users sorted by name
router.get('/', async (req, res) => {
	let users_to_return;
	const search_param = req.query.search;

	if(search_param)
		users_to_return = await User.fuzzySearch(search_param).select('-password');
	else
		users_to_return = await User.paginate({}, {...res.locals.pagination, sort: 'name', select: '-password' });

	log.silly(`Users', ${JSON.stringify(users_to_return)})`);
	log.silly(`Users', ${JSON.stringify(Envelope.paginated(users_to_return))}`);

	res.json(Envelope.paginated(users_to_return));
});

I am trying to do something like
users_to_return = await User.fuzzySearch(search_param).paginate({}, {...res.locals.pagination, select: '-password' });

Any ideas?

pre-existing data

Hi, thanks for the great plugin.
I've used pre-existing data update differently tough.
It uses Promise.all to update docs in database instead of async and queue from async as

follows:

const updateFuzzy = async (Model, attrs) => {
   const docs = await Model.find();

   const updateToDatabase = async data => {
      try {
         if(attrs && attrs.length) {
            const obj = attrs.reduce((acc, attr) => ({ ...acc, [attr]: data[attr] }), {});
            return Model.findByIdAndUpdate(data._id, obj).exec();
         }

         return Model.findByIdAndUpdate(data._id, data).exec();
      } catch (e) {
         console.error(e);
      }
   };

   await Promise.all(docs.map(doc => updateToDatabase(doc)));
}

// usage
updateFuzzy(User, ['firstName']);

can you consider it to update docs?
i've also tried to contribute with your project but count find a CONTRIBUTING.md and i dont have permissions to create branchs and create pull requests...
Can you also consider adding it?
thx, very much, hope hearing from you soon.

Having some doubts about the created index and internal behaviour

Hi, I just installed your plugin and making some unit testing with my use case I have some troubles. Let's say I have the next basic schema:

const articleSchema = new mongoose.Schema({
  title: {
    en: String,
    es: String,
  }
 // ... 
 otherProp: Boolean
}):

I want the fuzzy search to be in the two nested keys of the title, so I use the plugin according to your api:

articleSchema.plugin(fuzzySearch, {
  fields: [
    {
      name: 'title',
      keys: ['en', 'es'],
      minSize: 3
    }
  ]
});

Let's say i create the next document with title:

await new Article ({
  title: {
    en: 'This is an article title in english',
    es: 'A title that is supposed to be in spanish'
  }
},
// ...
).save();

After I check the database the n-grams are generated correctly and exist in the database.

 title_fuzzy: [
    {
      en_fuzzy: [
        'his',
        'thi',
        'this',
        'is',
        'an',
        'cle',
        'icl',
        'tic',
        'rti',
// ...
     ]

All cool, BUT when I did my testing, for example with the string 'cle' which is part of the n-grams array I have no results, not even when using more words, included in the n-gram array like: 'arti' or 'artic'. The only way I get results is by writing the whole word 'article' which afaik is the default behaviour of the native mongodb text search.

While doing more debugging I printed the generated indexes and with surprise I saw that the text index is in the original field, this is the index object I get back:

{
    v: 2,
    key: { _fts: 'text', _ftsx: 1 },
    name: 'title.es_text_title.en_text',
    ns: 'LocalTest.articles',
    background: true,
    weights: { 'title.en': 1, 'title.es': 1 },
    default_language: 'english',
    language_override: 'language',
    textIndexVersion: 3
  }

Am I doing something wrong? Or why the index is not pointed to the generated n-gram arrays? If not, what's happening?

Also, is there any way to override the default language? In the docs, mongo can work with different languages.

Thank you in advance.

Search in Referenced Object Id Field

Do you want to request a feature, an issue, or report a bug?
feature

What is the current behaviour?
Does not look into referenced object title or name.

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
Need to search in referenced object e,g; A product has field category (object Id) and if a user search for for example 'laptop' it should search for laptop in product name, keywords and title of category too, but the category filed id object id refernce.

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.

Feature Request

As a note , it was difficult to figure out the NGrams had not been built . As a suggestion an error should be returned if the ngrams are not found within the database.

No results returned with no search term (empty query)

Thanks so much for this package. Works super well from what I can tell!

I'm just having one issue. As demonstrated below, I have a find I replaced with fuzzySearch allowing users to perform a fuzzy search with a ?search=whatever query param. When that's not used, I want my fuzzySearch to return what would be returned by a find with no text search.

const acronyms = await Acronym.fuzzySearch(req.query.search || '')

Am I missing something? If there's a way to make this work, I'd love to know. Otherwise, I'd love some feedback on my PR to make this work: #42

Multiple pre-save hook issues

I have a pre-save hook that sets the value of 'this.contents' based on another field. Mongoose Fuzzy Search is set up to search based on 'this.contents'.

I think the pre-save hook that mongoose-fuzzy-searching requires to populate NGrams runs before the pre-save hook I created which populates 'this.contents'; therefore, no NGrams are populated.

Is there a way to specify which order the hooks run in? Can the mongoose-fuzzy-search middleware be post-save?

Fuzzy fields array are empty.

Hi, this looks like the plugin I need, unfortunately cannot get it working, see Schema below:

const crypto = require('crypto');
const mongoose = require('mongoose');
const mongoose_fuzzy_searching = require('mongoose-fuzzy-searching');

const userSchema = new mongoose.Schema({
  email: { type: String, unique: true },
  password: String,
  passwordResetToken: String,
  passwordResetExpires: Date,
  emailVerificationToken: String,
  emailVerified: Boolean,

  profile: {
    name: String,
    firstName: String,
    secondName: String,
  }
}, { timestamps: true });

userSchema.plugin(mongoose_fuzzy_searching, { fields: ['profile.firstName', 'profile.secondName'] });

I can see firstName_fuzzy and the second field created but both are empty. I deleted old indexes for firstName and secondName.

Should this be populated straight after adding new user or updating one?

How to use with Aggregation?

Do you want to request a feature, an issue, or report a bug?
A feature

What is the current behaviour?
Doesn't work with aggregate

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?

  • should work with aggregation pipeline with pagination (skip & limit)

If this is a feature request, what is the motivation or use case for changing
the behaviour?

  • Let say I am using an aggregation pipeline for a query and want to filter data based on search

Please mention other relevant information such as Node.js and mongoose version.

Update mongoose version to 6.x.x

Do you want to request a feature, an issue, or report a bug?
Issue

What is the current behaviour?
Outdated mongoose peer dependency version.

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
Please update this version

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Support for newest mongoose version.

Please mention other relevant information such as Node.js and mongoose version.

Format data before making ngrams

Do you want to request a feature, an issue, or report a bug?
feature
What is the current behaviour?
Ngrams are created directly from data

What is the expected behaviour?
Having an option to format or parse data first

If this is a feature request, what is the motivation or use case for changing
the behaviour?

For example, I want to search by date by writing the date in a certain format i.e: 'DD/MM/YYYY', therefore having an option to format the field as I like would be a really useful feature

I.E

{
  name: 'date',
  format: date => dayjs(date).format('DD/MM/YYYY') 
}

I can work on this feature if we agree that is relevant and on how it's going to be implemented

Results accuracy

Do you want to request a feature, an issue, or report a bug?
issue

What is the current behaviour?
I cant find a way to improve results accuracy.
I'm using this package to get users that have email similar to a particular one.
I would like to find something like "[email protected]" and "[email protected] as match of "[email protected]", but right now i got matches really different from my search email.
I can even find null values in results.
I tried to change minsize and weight values unsuccessfully

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.
Using mongo 3.6, node 10.23 and version 2.0.2 of this package.

How can I implement the partial index on this package ?

Do you want to request a feature, an issue, or report a bug?

What is the current behaviour?

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Please mention other relevant information such as Node.js and mongoose version.

Any way to use projections on the fuzzySearch function?

Do you want to request a feature, an issue, or report a bug?
New feature

What is the current behaviour?
Model.fuzzySearch() doesn't provide projections.

If the current behaviour is a bug, please provide the steps to reproduce.

What is the expected behaviour?
To accept projections through Model.fuzzySearch() parameters.

If this is a feature request, what is the motivation or use case for changing
the behaviour?

Makes the API more in-line with Mongoose API and results in less repetitive and cleaner code.

Please mention other relevant information such as Node.js and mongoose version.
Node: 12.13.1
Mongoose: 5.9.25

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.