Search in mongoosastic doesn't give any result - node.js

I tried to use mongoosastic search but it doesnt work
Job.js (Mongoose schema)
var mongoose = require('mongoose');
var mongoosastic = require('mongoosastic');
var Schema = mongoose.Schema;
var JobSchema = Schema({
title: { type: String, es_indexed:true },
category: { type: Schema.Types.ObjectId, ref: 'Category', es_indexed:true},
salary: { type: String, es_indexed:true },
});
JobSchema.plugin(timestamps);
JobSchema.plugin(mongoosastic, {
hosts: [
'localhost:9200'
]});
module.exports = mongoose.model('Job', JobSchema);
Routes.js
var express = require('express');
var app = express();
var Job = require('../models/job');
Job.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);
}
});
app.post('/api/search/', function(req, res, next) {
Job.search({query_string: {query: req.body.test}}, function(err, results) {
if (err) return next(err);
res.send(results);
});
});
This is the data sets that already been saved in mongodb
{
"id": 12313,
"title": "Engineer"
},
{
"id": 13123,
"title": "Doctor"
},
{
"id": 121243134,
"title": "Software Engineer"
}
When I tried to run the search and search like "Engineer" and I keep getting this result.
Updated for Curl
curl -XGET localhost:9200/_mapping
curl -XGET localhost:9200/_search

Since title is an analyzed String, its value is indexed using the standard analyzer, i.e. in lowercased form, so "Engineer" will be indexed and "engineer"
Try searching for "engineer" in lowercase instead.
UPDATE
Based on our discussion, it seems that the problem is simply that your Elasticsearch is empty. Since you have existing data in MongoDB, you need to make sure to call the synchronize() method on your model in order to index all your MongoDB collection inside Elasticsearch.

Related

Handling arrays with express post request

I'm using express to make the API for my web app. Below is the Schema for my annual budgets collection.
var {mongoose} = require('../db/mongoose');
var budgets = new mongoose.Schema({
year: Number,
categories: [{
name: String,
amount: Number
}]
});
var Budgets = mongoose.model('Budgets', budgets);
module.exports = {
Budgets
};
I am trying to passing in an array of categories using postman in the following way:
{
"year":2018,
"categories": [{
"name":"Logistics",
"amount":1500
}, {
"name":"Finance",
"amount":23030
}]
}
This the post request for my this collection. The request times out and is not saved in the database. I cannot seem to figure out what is wrong with the request. Please help
app.post('/annualBudgets', (req, res) => {
var categories = req.body.categories;
var budgets = new Budgets({
year : req.body.year,
});
budgets.categories.push(categories);
budgets.save().then((docs) => {
res.send(docs);
console.log(docs)
}).catch((e) => res.status(404));
});
The problem is here
budgets.categories.push(categories);
it should be
budgets.categories = categories;
// Alternatively
// budgets.categories.push(...categories);
because categories is already an array.

node.js mongoose subfield in a document

I have been working with node.js and mongoose for sometime and I am hitting a wall. I have a database with 20,000 documents and when i search the database from the cli it works fine.
db.Tickets.find({ "Customers.Customer.CustomerID" : '123123123' })
This returns 256 results
Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema for Ticket
var Ticket = new Schema({
UserName: {
type: String
},
Status: {
type: String
},
TicketNumber: {
type: Number
},
Name: {
type: String
},
Description: {
type: String
},
TicketTypeName: {
type: String
},
DueDate: {
type: Date
},
MapCollectDate : {
type: Date
},
NumberofUsersAffected : {
type: Number
},
DNNumber : {
type : String
},
RevisionDate : {
type : Date
},
CommercialImpact : {
type: String
},
Customers :[{
Customer: [{
CustomerID: Number,
CustomerName: String
}]
}],
Although if I test this in node.js using mongoose. I can't get it to return anything
I have a generic search that works
Ticket.find(function (err, tickets){
But can't get the specific search to work.
I am Connecting to Mongo
const config = require('./db');
//const Course = require('./models/Course');
//const CourseRoute = require('./routes/CourseRoute');
const Ticket = require('./models/Ticket');
const TicketRoute = require('./routes/TicketRoute');
const PORT = 4000;
mongoose.connect(config.DB).then(
() => {console.log('Connected to MongoDB') },
err => { console.log('Error connecting to MongoDB' +err)
});
Output of the log
Your node js server is running on PORT: 4000
Connected to MongoDB
Connected to MySQL
My Route End point
router.route('/').get(function (req, res) {
Ticket.find({ "Customers.Customer.CustomerID" : global.auth_username }, function(err, ticket) {
if(err){
console.log(err);
}
else {
res.json(tickets);
}
});
});
Also tried without the variable
router.route('/').get(function (req, res) {
Ticket.find({ "Customers.Customer.CustomerID" : "123123123" }, function(err, ticket) {
if(err){
console.log(err);
}
else {
res.json(tickets);
}
});
});
I had the same issue when I forgot to connect to Mongoose before running query
mongoose.connect(MONGO_URL, mongoOptions)
.then(() => {
// do your thing here
})
You had over a year to figured this out, and I am sure that you did so, but either way it seems that you have a typo in your code. The callback parameter is named ticket - function(err, ticket) {, whereas you are logging tickets - res.json(tickets);. In the generic test you correctly wrote tickets - Ticket.find(function (err, tickets){, which is probably why it worked.
The takeaway lesson here is - use debugging tools instead of logging, makes it easier to catch such problems.
Also, it would be appropriate to answer your own question once you've figured it out. But given that this is probably completely useless, you might as well delete it. Cheers!

Mongoose update query keeps on inserting data with upsert true without updating and adding only 1 field

I am working on Facebook login in Node js with Mongoose. i am getting issues while updating data.
This is my Scheme file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Schema
var RegSchema = mongoose.Schema({
UserName: String,
UserEmail: String,
userprofileImage : String,
userId: String,
reg_time : {
type : Date, default: Date.now
}
}, { collection: 'user' });
// Model
module.exports = mongoose.model('UserReg', RegSchema);
and this is my main file where update and insert(if not found) is placed
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var UserReg = require('./myschema.js');
module.exports = function(userdetail, callback){
var bb;
var UserAdd = new UserReg({
"UserName": userdetail.username,
"UserEmail": userdetail.useremail,
"userId": userdetail.userId,
"userprofileImage": userdetail.userprofileImage
});
var userdetailchange = {
"UserName": userdetail.username,
"UserEmail": userdetail.useremail,
"userId": userdetail.userId,
"userprofileImage": userdetail.userprofileImage
};
// Update if found otherwise Insert
UserAdd.update({"userId":userdetail.userId },{ $set:userdetailchange, $setOnInsert:userdetailchange ,upsert:true, new: true, setDefaultsOnInsert: true}, function (err, data) {
if (err) {
callback(err);
}
callback(data);
});
};
Now it keeps on inserting user data in collection with only 1 field which is userId and also a default _id field. Please help me in updating whole data if match found or Insert whole data in Collection. Any help will be highly appreciated.
upsert, new and setDefaultsOnInsert are options, which need to be passed in a separate, third argument to update (documented here):
UserReg.update({
"userId" : userdetail.userId // query document
}, {
$set : userdetailchange, // update document
$setOnInsert : userdetailchange
}, {
upsert : true, // options
new : true,
setDefaultsOnInsert : true
}, function (err, data) {
...
});

MongoDB and Nodejs insert ID with auto increment

I am new to NodeJs and MongoDB, i want to insert row with auto increment primary key 'id'. also defined a function called getNextSequence on mongo server.
this is working perfect on Mongodb server
> db.user.insert({
"id" : getNextSequence('user_id'),
"username" : "test",
"email" : "test#test.com",
"password" : "test123"
})
now i want to insert from NodeJs.I have tried this but not working
db.collection('user').insertOne({
id : "getNextSequence('user_id')",
username : query.name,
email: query.email,
password: query.pass
}, function(err, result) {
assert.equal(err, null);
console.log("row insterted ");
callback();
});
Assuming that getNextSequence is a server-script function (i.e. a method you defined and saved via db.system.js.save), it is not callable outside of the server. One way to go is to use eval, which forces the server to evaluate a string as a js code, even though it is not a good practice. Here is an example:
db.eval('getNextSequence(\'user_id\')', function(err, result) {
db.collection('users').insert({
"id" : result,
"username" : "test",
"email" : "test#test.com",
"password" : "test123"
});
});
Another way is to follow the mongo tutorial and to implement the getNextSequence directly in NodeJS. The syntax is pretty much the same:
function getNextSequence(db, name, callback) {
db.collection("counters").findAndModify( { _id: name }, null, { $inc: { seq: 1 } }, function(err, result){
if(err) callback(err, result);
callback(err, result.value.seq);
} );
}
You then use it in your nodeJS code like:
getNextSequence(db, "user_id", function(err, result){
if(!err){
db.collection('users').insert({
"_id": result,
// ...
});
}
});
Note: of course, you need to have set the counters collection as explained in the docs.
You can also use "mongoose-auto-increment".
The code has just 4 lines
var mongoose = require('mongoose');
var autoIncrement = require('mongoose-auto-increment');
autoIncrement.initialize(mongoose.connection);
userSchema.plugin(autoIncrement.plugin, 'user');
example :
npm i mongoose-auto-increment
connections.js :
const mongoose = require('mongoose');
require("dotenv").config;
const uri = process.env.MONGOURL;
mongoose.connect(uri, { useNewUrlParser: true }, (err) => {
if (!err) { console.log('MongoDB Connection Succeeded.') }
else { console.log('Error in DB connection : ' + err) }
});
require('../schema/userSchema');
userSchema.js :
var mongoose = require('mongoose'); // 1. require mongoose
var autoIncrement = require('mongoose-auto-increment'); // 2. require mongoose-auto-increment
var userSchema = new mongoose.Schema({
name: { type: String },
password: { type: String },
email: { type: String, unique: true, required: 'This field is required.' },
});
autoIncrement.initialize(mongoose.connection); // 3. initialize autoIncrement
userSchema.plugin(autoIncrement.plugin, 'user'); // 4. use autoIncrement
mongoose.model('user', userSchema);
To accomplish this, we will create a function that will keep trying to save the document untill it will have been saved with incremented _id
async function retryUntilSave(db, task) {
try {
const index = await db.collection('tasks').find().count() + 1;
const result = await db.collection('tasks').insertOne(Object.assign(task, { _id: index }))
} catch (error) {
if (error.message.includes("_id_ dup key")) {
console.log("ID already exists!")
console.log("Retrying...");
retryUntilSave(db, task)
} else {
console.log(error.message);
}
}
}
We can use task._id: index instead of Object.assign()
finally you can test this by making some concurrent requests
for (let index = 0; index < 20; index++) {
setTimeout(async () => {
await retryUntilSave(db, { title: "Some Task" })
}, 1000);
}
This function will handle easily if two or more tasks submitted at the same time because mogod throws error when we try to insert a document with duplicate _id, then we will retry saving the document again with incremented _id and this process will run until we save the document successfully !
You can also use "mongodb-autoincrement" module of node js. For example:
var autoIncrement = require("mongodb-autoincrement");
exports.yourMethod = function(newData, callback) {
autoIncrement.getNextSequence(db, your-collection-name, function (err, autoIndex) {
newData.id = autoIndex;
//save your code with this autogenerated id
});
}
You can use the below package on a model schema to auto-increment your collection field.
mongoose-auto-increment //you can download it from npm
Here I am not focusing on how to connect MongoDB. I just focus on how you can integrate auto increment in your model/collection/table.
const mongoose = require("mongoose"); //
const autoIncrement = require("mongoose-auto-increment");
const post_schema = new mongoose.Schema({
title: {
type: String,
required: true,
min: 3,
max: 225,
},
slug: {
type: String,
required: true,
},
});
autoIncrement.initialize(mongoose.connection);
post_schema.plugin(autoIncrement.plugin, {
model: "post", // collection or table name in which you want to apply auto increment
field: "_id", // field of model which you want to auto increment
startAt: 1, // start your auto increment value from 1
incrementBy: 1, // incremented by 1
});
module.exports = mongoose.model("post", post_schema);

Finding a MongoDB document by ObjectId with Mongoose

I am trying to update a document in MongoDB by finding it by the ObjectId. The work flow is as follows (this is for a blog).
Create a new post in MongoDB by passing a title and body. The ObjectId is automatically created.
Go to edit the post. It uses the ObjectId from the URL to grab it from the database and display it in the same new post form, just with the preexisting values.
When the submit button is clicked I want to find the document by the ObjectId and update the values in the database with those in the post form.
Step 1 & 2 work fine, but step 3 doesn't seem to be working. It redirects to the page I need it to. But the database has not been updated. It's the same value as it was before.
Here's the relevant code for the update post portion:
app.js
app.post "/office/post/:id/update", ensureAuthenticated, routes.updatePost
routes/index.js
mongoose = require 'mongoose'
ObjectId = mongoose.Types.ObjectId
Post = require '../models/Post'
...
updatePost: function(req, res) {
var o_id, the_id;
the_id = req.params.id;
console.log(the_id); // 510e05114e2fd6ce61000001
o_id = ObjectId.fromString(the_id);
console.log(o_id); // 510e05114e2fd6ce61000001
return Post.update({
"_id": ObjectId.fromString(the_id)
}, {
"title": "CHANGE"
}, res.redirect("/office/edit/posts"));
}
I'm using Express and Mongoose.
This is also the post model if that helps:
(function() {
var Post, Schema, mongoose;
mongoose = require('mongoose');
Schema = mongoose.Schema;
Post = new Schema({
title: String,
subhead: String,
body: String,
publish_date: {
type: Date,
"default": Date.now
},
mod_date: {
type: Date,
"default": Date.now
}
});
module.exports = mongoose.model('Post', Post);
}).call(this);
And here's the code for the edit blog post view:
app.js
app.get("/office/post/:id/edit", ensureAuthenticated, routes.editPost);
routes/index.js
editPost: function(req, res) {
return Post.findById(req.params.id, function(err, post) {
return res.render('edit-post', {
post: post,
title: post.title
});
});
}
The problem is how you call update
return Post.update({
"_id": ObjectId.fromString(the_id)
}, {
"title": "CHANGE"
}, res.redirect("/office/edit/posts"));
The last argument will actually redirect the page, whereas update expects a function to be called when the update is complete
You should pass in
return Post.update({
"_id": ObjectId.fromString(the_id)
}, {
"title": "CHANGE"
}, function(err, model) {
if (err) // handleerr
res.redirect("/office/edit/posts"));
});
That way, we only redirect once the model is successfully updated

Resources