Fuzzy search in full text search using mongoosastic - node.js

I've been working on a website with a search feature which matches the queries with the various article present in MongoDB. currently mongoDB does not support fuzzy search with is what I want with my search feature. For that I've found that Elasticsearch works the best with this type of problem. I've use mongoosastic client for the node.js for this purpose. I was able to save data item and search the query but it can't search if there is any spelling mistake present in it. How can I customise the query that help finding the text even with some typo or word missing.
const mongoose = require('mongoose');
const mongoosastic = require('mongoosastic');
mongoose.connect('mongodb://localhost:27017/mongosync');
var UserSchema = new mongoose.Schema({
name: String
, email: String
, city: String
});
UserSchema.plugin(mongoosastic, {
"host": "localhost",
"port": 9200
}, {hydrate:true, hydrateOptions: {lean: true}});
var User = mongoose.model('user', UserSchema);
// User.createMapping((err, mapping) => {
// console.log('mapping created');
// });
// var newUser = new User({
// name: 'Abhishek',
// email: 'abhishek.patel#company.com',
// city: 'bhopal'
// });
// newUser.save((err) => {
// if(err) {
// console.log(err);
// }
// console.log('user added in both the databases');
// })
// newUser.on('es-indexed', (err, result) => {
// console.log('indexed to elastic search');
// });
User.search(
{query_string: {query: "abheshek"}},
function(err, results) {
if(err){
console.log('ERROR OCCURED');
} else {
console.log(results);
}
});

I think this will help :)
Place.search({
match: {
name: {
query: q,
fuzziness: "auto"
}
}
}, (err, results) => {
if (err) return next(err);
const data = results.hits.hits.map(hit => hit);
// return res.json(data);
return res.status(200).json({locations: data});
});

Related

MongoDB update if user not exists

I have a problem to update user if his/her name is not available in my database
I thought if my function "User.findOne" doesn't find a user in my mongodb it can update database. Unfortunately nothing happens. I get only output "Hello Anna you are new here!" My name is not saved into my mongodb
Could somebody smart give me please a tip how can I save username if it is not in my database
var User = require('./user');
var myName = this.event.request.intent.slots.first_name.value;
self = this;
User.findOne({ name: myName }, function(err, user) {
if (err ||!user){
var userSave = new User({
name: myName
});
userSave.save(function (err, results) {
console.log(results);
self.emit(':ask',
"Hello "+ myName +"you are new here!")
});
}
else {
self.emit(':ask',
"Hello "+ myName +" you are not new!")
}
});
My mongoose model code:
//user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect("mongodb://c******mlab.com:***/users");
var userSchema = new Schema({
name: String,
userId: { type: String, required: false, unique: true }
});
var User = mongoose.model('User', userSchema);
module.exports = User;
var User = require('./user');
var myName = this.event.request.intent.slots.first_name.value;
self = this;
User.findOne({
name: myName
}, (err, user) => {
if(err) throw err;
if(user) {
self.emit(':ask', `Hello ${myName} you are not new`);
} else {
User.create({
name: myName
}, (err, result) => {
if(err) throw err;
console.log(result);
self.emit(':ask', `Hello ${myName} you are new here!`);
})
}
});
this should work.
The line if (err || !user) is confusing to read, and in this style you're mixing error handling (if (err)) and a condition in your code that you expect to hit (if (!user)). I suggest you separate them so the code is easier to read and debug.
For example, using plain Javascript and the MongoDB node driver:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost/test', function(err, conn) {
// connection error handling
if (err) {
console.log('Connection error: ' + err);
}
conn.db('test').collection('test').findOne({name:'abc'}, function(err, doc) {
// findOne error handling
if (err) {
console.log('Error: ' + err);
}
// if document exists
if (doc) {
console.log('Document found: ' + JSON.stringify(doc));
}
// if document doesn't exist
else {
console.log('Document not found');
}
conn.close();
});
});
If the database contains the user abc, the output would be:
$ node script.js
Document not found
If the user abc exists:
$ node script.js
Document found: {"_id":0,"name":"abc"}
I believe using a similar pattern you can modify your code to do what you need.

two way navigation in a mongo one to n relashionship

I'm having hard times with the mongoose relashionship system.
Here are my schemes:
const mongoose = require('mongoose');
const RecipeSchema = mongoose.Schema({
Title: { type: String },
Description: { type: String },
Complaints: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Complaint' }]
});
const Recipe = mongoose.model('Recipe', RecipeSchema);
const ComplaintSchema = mongoose.Schema({
Recipe : { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
Message: { type: String }
});
const Complaint = mongoose.model('Complaint', ComplaintSchema);
And here are how I'm saving my data:
var recipeEntity = new Recipe({
Title: request.body.Title,
Description: request.body.Description
});
recipeEntity.save();
var complaintEntity= new Complaint({
Message: request.body.Message.trim(),
Recipe: mongoose.Types.ObjectId(request.body.Message.RecipeId);
});
complaintEntity.save();
So far, so good... at least to me!
And now, when I try to list the recipes with the complaints, I just got an empty array of complaints:
Recipe
.find()
.populate('Complaints')
.exec(callback);
And here is the json result:
[{
"Id": "595fe6f89d63700011ee144d",
"Title": "Chocolate Cake",
"Description": "aaaa bbb cc d"
"Complaints": []
}]
So, what am I missing here?
tks for your support
I am going to assume that you are not saving both recipe and complaint during the same call. That would not make any sense: everytime you make a complaint, you wouldn't make a recipe too.
When you create a complaint, you need to save its associated recipe's ObjectId AND also add/push the complaint's ObjectId into the associated recipe's complaints.
If you are following resource naming conventions, you would have something like:
// get recipes including complaints
app.get('/recipes', function (req, res) {
Recipe.find().populate('Complaints').exec(function (err, recipes) {
console.log(recipes);
});
});
// add recipe
app.post('/recipes', function (req, res) {
var recipe = new Recipe(req.body); // simplified
recipe.save(function (err) {
if (err)
return res.send(err);
res.send('ok');
});
});
// add complaint for recipe
app.post('/recipes/:recipeID/complaints', function (req, res) {
// we query recipe bc we need it after
Recipe.findById(req.params.recipeID, function (err, recipe) {
if (err)
return res.send(err);
if (!recipe)
return res.send('No recipe found');
// add complaint
var complaint = new Complaint(req.body);
complaint.Recipe = recipe._id; // add reference in one direction
complaint.save(function (err) {
if (err)
return res.send(err);
// update recipe
recipe.Complaints.push(complaint._id); // add reference in other direction
recipe.save(function (err) {
if (err)
return res.send(err);
res.send('ok');
});
});
});
})
I think this is a good read: many to many relationship with nosql (mongodb and mongoose).
OK, how I had to save the record in the reference too, I adopted this approach:
RecipeSchema.pre('remove', function(next) {
Complaint.remove({ "Recipe" : this._id }).exec();
next();
});
ComplaintSchema.pre('remove', function(next) {
Recipe.findById(this.Recipe).exec((error, item) => {
var index = item.Complaints.indexOf(item.Complaints.find(e => e._id == this._id));
item.Complaints.splice(index, 1);
item.save(() => { next(); });
});
});
ComplaintSchema.pre('save', function(next) {
Recipe.findById(this.Recipe).exec((error, item) => {
item.Complaints.push(this);
item.save(() => { next(); });
});
});
using this trigger/event available on the mongo schemas.
That worked perfectly!

Duplicated entries in referenced array - MongoDB - Mongoose

I'm new to MongoDb and I met this problem days ago and I can't resolve it. Basically, my user is allowed to create new Post with a bunch of Images. When I create the Post, then I create also the Images but when I check on mongo shell the entries in the array of the Post, one image can be present two or three times. (All the images are saved with an url)
These are my Models:
var postSchema = new mongoose.Schema({
Name: String,
Background: String,
Description: String,
posted: {type:Date,default: Date.now() },
images: [{type: mongoose.Schema.Types.ObjectId, ref: "image"}]
});
var imageSchema = new mongoose.Schema({
src: String,
caption: String
});
(These Schema are in separeted files and then exported as model)
This is my code for saving Post:
app.post("/post",isLoggedIn,function(req,res){
var post= {Name: req.body.name,
Background: req.body.backg,
Description: req.body.desc};
Posts.create(post, function(err, newPost){
if(err){
console.log(err);
} else {
var allImages = req.body.img;
allImages.forEach(function(singleImg){
Images.create(singleImg, function(err, newImg){
if(err){
console.log(err);
} else {
newPost.images.push(newImg);
newPost.save(function(err){
if(err){
return res.send(err);
}
});
}
});
});
}
});
return res.redirect("/posts");
});
Edit
This is my code with $addToSet
app.post("/post",isLoggedIn,function(req,res){
var post= {Name: req.body.name,
Background: req.body.backg,
Description: req.body.desc};
Posts.create(post, function(err, newPost){
if(err){
console.log(err);
} else {
Posts.findByIdAndUpdate(newPost._id, {$addToSet:{images: {$each: req.body.img}}}, function(err, updatedPost){
return res.redirect("/posts");
});
}
});
});
It gives me CastError Cast to ObjectId failed
Don't forget hanlde errors
Edit your code: (With Mongoose + nodejs - I suggest use indexOf, It runs very well with me, My DB have about 10M records)
From
Posts.create(post, function(err, newPost){
if(err){
console.log(err);
} else {
var allImages = req.body.img;
allImages.forEach(function(singleImg){
Images.create(singleImg, function(err, newImg){
if(err){
console.log(err);
} else {
newPost.images.push(newImg);
newPost.save(function(err){
if(err){
return res.send(err);
}
});
}
});
});
}
});
to
Posts.create(post, function(err, newPost){
if(err){
console.log(err);
} else {
var allImages = req.body.img;
allImages.forEach(function(singleImg){
Images.create(singleImg, function(err, newImg){
if(err){
console.log(err);
} else {
// Check exist
if (newPost.images.indexOf(newImg._id) == -1) {
newPost.images.push(newImg._id);
newPost.save(function(err){
if(err) {
return res.send(err);
}
});
} else {
console.log(newImg);
// do something
}
}
});
});
}
});
OR
Use $addToSet if you use MongoDb or Mongoose
Hope it will help you.
Thank you

Mongoose find not working with ObjectId

I have one schema defined in userref.js
module.exports = (function userref() {
var Schema = mongoose.Schema;
var newSchema= new Schema([{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
index: true
},
value: { type: Number }
}]);
var results = mongoose.model('UserRef', newSchema);
return results;
})();
I have inserted some data and when I try to fetch some data I am getting proper values from mongodb console
db.getCollection('userrefs').find({'userId':ObjectId('57a48fa57429b91000e224a6')})
It returns properly some data
Now issue is that when I try to fetch some data in code by giving objectId I am getting empty array. In below function userrefs is returned as empty array
//req.params.userId=57a48fa57429b91000e224a6
var UserRef = require('../userref.js');
this.getuserref = function (req, res, next) {
try {
var o_userId =mongoose.Types.ObjectId(req.params.userId);
var query = { userId: o_userId };
var projection = '_id userId value';
UserRef.find(query, projection, function (err, usrrefs) {
if (err) return next(err);
res.send(usrrefs);
console.log("userref fetched Properly");
});
} catch (err) {
console.log('Error While Fetching ' + err);
return next(err);
}
};
Also when I debug code I can see o_userId as objectId with id value as some junk character
o_userId: ObjectID
_bsontype: "ObjectID"
id: "W¤¥t)¹â$¦"
Try this:
try {
var o_userId =mongoose.Types.ObjectId(req.params.userId);
var query = { userId: o_userId };
var projection = '_id $.userId $.value';
UserRef.find(query, projection, function (err, usrrefs) {
if (err) return next(err);
res.send(usrrefs);
console.log("userref fetched Properly");
});
} catch (err) {
console.log('Error While Fetching ' + err);
return next(err);
}
Add the export like this
module.exports.modelname= mongoose.model('userrefs', nameofschema, 'userrefs');
var z = require('../userref.js');
var UserRef = z.modelname;
Now call using UserRef.
Just simply try this man.
Model.find({ 'userId': objectidvariable}, '_id userid etc', function (err, docs) {
// docs is an array
});
Reference sample copied from their official doc.

I received an error when I delete an index from elasticsearch

I received an error when I manually deleted an index from elasticsearch. This happen after manually deleted and I use User.search function in the route. This is the error:
Error: [search_phase_execution_exception] all shards failed
The reason why I manually deleted the index is because mongoosastic has a known issue where, whenever I delete documents from mongodb, elasticsearch still has the documents with it.
Here's the code
models/user.js
var mongoose = require('mongoose');
var mongoosastic = require('mongoosastic');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
private: false,
twitter: String,
tokens: Array,
username: String,
displayName: String,
picture: String,
});
UserSchema.plugin(mongoosastic, {
hosts: [
'localhost:9200'
]});
module.exports = mongoose.model('User', UserSchema);
router.js
User.createMapping(function(err, mapping) {
if (err) {
console.log('error creating mapping (you can safely ignore this)');
console.log(err);
} else {
console.log('mapping created!');
console.log(mapping);
}
});
var stream = User.synchronize();
var count = 0;
stream.on('data', function(err, doc){
count++;
});
stream.on('close', function(){
console.log('indexed ' + count + ' documents!');
});
stream.on('error', function(err){
console.log(err);
});
/* The result for searching for User's */
router.get('/search', function(req, res, next) {
console.log(req.query.q);
if (req.query.q) {
User.search({
query_string:
{ query: req.query.q }
}, function(err, results) {
if (err) return next(err);
console.log(results);
var data = results.hits.hits.map(function(hit) {
return hit;
});
console.log(data);
return res.render('main/search_results', { data: data });
});
}
});

Resources