Elasticsearch returns IndexMissingException - node.js

I'm trying to implement a search engine in node.js using elasticSearch + mongoose which is elmongo. Whenever i try to run a search api i get
"error": "IndexMissingException[[ads] missing]"
Here's the code
advertisingSchema.js
var mongoose = require('mongoose');
var elmongo = require('elmongo');
var Schema = mongoose.Schema;
var AdSchema = new Schema({
title: String,
description: String,
category: String,
phoneNumber: { type: Number, unique: true},
photos: [{ type: String }],
created: { type: Date, default: Date.now},
price: Number,
password: String
});
AdSchema.plugin(elmongo);
module.exports = mongoose.model('Ad', AdSchema
);
api.js
var Ad = require('../models/advertising');
module.exports = function(app, express) {
var api = express.Router();
Ad.sync(function(err) {
console.log("Check the number sync");
})
api.post('/search', function(req, res) {
Ad.search(req.body, function(err, result){
if(err) {
res.send(err);
return;
}
res.json(result);
});
});
return api;
}
I've done everything correctly, but its just doesn't want to return the search result.

As the error suggest there is no index named 'ads' in your cluster. Index is automatically created unless you have set the property "action.auto_create_index" to false in your elasticsearch configuration. You can create the index programmatically or by running a curl request.
Refer to create index api.

Related

How can you render items only if matching category?

I'm trying to build an ecommerce shop using express and mongodb. I'm trying to make categories for the shop. (e.g when someone clicks a category it should only display the items corresponding to that category) I've tried multiple ways to tackle this issue but haven't found a solution.
My current code is this one:
var NFTitem = require("../models/NFTitem")
var Item = require('../models/item');
var async = require('async')
exports.item_list = function(req, res, next) {
async.parallel({
item: function(callback) {
Item.find({}).exec(callback);
},
collection_list: function (callback) {
NFTitem.find({}).exec(callback);
},
collection: function(callback) {
NFTitem.find({'_id' : req.params.id }).exec(callback)
},
thisCategory: function (callback) {
Item.find({'collectionItem' : req.params.id }).exec(callback);
},
}, function(err, results) {
res.render('item_list.jade', { title: "NFT Marketplace", collection_list: results.item});
})
}
Now the logic behind this is to find the items corresponding to the items database which is (Item) and extract it, finding only the id matching the categories database. Then we would find the id for the categories database which is (NFTitem). Then we would do and if else command so that it only shows if both ids are matching. But this method doesn't seem to work.
I've also tried filtering the thing but it displays nothing when i filter it out. I would like to know what would be the best solution for this and if there's any way I could solve this issue.
rendered website:
block content
h1= title
ul
each collection in collection_list
li
a(href=collection.url) #{collection.name}
models for items:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ItemSchema = new Schema(
{
name: {type: String, required: true},
description: {type: String, required: true},
collectionItem: {type: Schema.Types.ObjectId, ref: 'nftitem', required: true},
price: {type: Number, required: true},
instock: {type: Number, required: true},
}
);
// Virtual for book's URL
ItemSchema
.virtual('url')
.get(function () {
return '/catalog/item/' + this._id;
});
//Export model
module.exports = mongoose.model('Item', ItemSchema);
models for collections:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var NFTItemSchema = new Schema(
{
name: {type: String, required: true},
description: {type: String, required: true},
}
);
// Virtual for book's URL
NFTItemSchema
.virtual('url')
.get(function () {
return '/catalog/nftitem/' + this.name;
});
//Export model
module.exports = mongoose.model('nftitem', NFTItemSchema);
Since the collectionItem field in Item Schema is a reference to NFTItemSchema Schema, you can query Item Collection directly. You can refactor and simplify your code like this:
const Item = require('../models/item');
exports.item_list = async (req, res, next) => {
try{
let all_items = await Item.find({collectionItem: req.params.id});
res.render('item_list.jade', { title: "NFT Marketplace", collection_list: all_items });
} catch (error) {
res.status(400).json(error: error);
}
}

Mongoose / Express findByIdAndUpdate does not work

I tried methods from Stackoverflow and many other sites, but I could not change the data in my database. I am sending the ID of the product in my database to the specified API. However, nothing is returning. The data is also not updated with the data in the new JSON file I entered. I'm testing it using Postman.
This is my API code from my server.js file.
app.put("/api/product/update", (req, res) => {
Product.findByIdAndUpdate(req.params.id, req.body, function (err, doc) {
res.send(doc);
});
Here is my model file:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const productSchema = mongoose.Schema({
name: {
required: true,
type: String,
unique: 1,
//maxlength
},
material: {
type: Array,
default: []
},
price: {
type: Number,
required: true,
maxlength: 255,
},
productType: {
type: Schema.Types.ObjectId,
ref: 'Prodtype',
default: "Other",
},
inStock: {
type: Boolean,
default: true,
}
},{timestamps:true});
const Product = mongoose.model('Product',productSchema);
module.exports = { Product }
Postman: PUT localhost:3000/api/product/update?id=6029812bee921b0c7fb65abf
Based on the information you've provided I'm assuming you're using express as your nodejs server framework.
If you want to access your request body, you need to add a body-parser as a middleware.
$ npm i body-parser
const bodyParser = require('body-parser')
app.use(bodyParser)
app.put("/api/product/update", (req, res) => {
Product.findByIdAndUpdate(req.params.id, req.body, function (err, doc) {
res.send(doc);
});
In addition I would recommend you to not directly write everything you're receiving on the endpoint to your database but to implement some sort of validation.
I solved my problem. When I changed my code as follows, I used req.query instead of req.body.
app.put("/api/product/update",(req, res) => {
Product.findByIdAndUpdate(
{ _id: req.query.id },
{ name: req.body.name, price: req.body.price, inStock: req.body.inStock },
function (err, doc) {
console.log(doc);
if (err) {
console.log(err.message);
} else {
res.send(doc);
}
}
);
});

Accessing Schema.Types.ObjectId's values with Mongoose

Hi I'm learning MongoDB and how to use Mongoose,
I'm trying to build a simple Workout manager app, where workouts have a name (Eg: "Upper Body"), an email account (which is used to identify who created the workout) and array of exercise consisting of references to exercises.
I want to be able to have a query where I can access the exercise title(Eg: "Push Ups") by using just the workout name.
My workout.js Model:
var mongoose = require('mongoose');
const Schema = mongoose.Schema;
var Exercise = require('./exercise');
const workoutSchema = new Schema({
title: {type: 'String', required: true},
email: {type: 'String', required: true},
exercises: [{ type: Schema.Types.ObjectId, ref: 'Exercise' }],
});
module.exports = mongoose.model('Workout', workoutSchema);
My exercise.js Model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var exerciseSchema = new mongoose.Schema({
title: {type: String, required: true}
}, {
timestamps: true
});
module.exports = mongoose.model('Exercise', exerciseSchema);
My Workout Controller looks like this :
var Workout = require('../models/workout');
var Exercises = require('../models/exercise');
exports.getWorkoutExercises = function(req, res) {
Workout.findOne({ title: req.params.workout_name})
.populate('exercises')
.exec((err, exercises) => {
if (err){
res.send(err);
}
/* I want to be able to return or access the exercises title */
res.json({exercises.title});
});
}
In My routes.js i have this :
workoutRoutes.get('/:workout_name', WorkoutController.getWorkoutExercises);
Any Help or tips is much appreciated !
I am not sure what you did here res.json({exercises.title}); Can you try this? Hope it works
Workout.findOne({ title: req.params.workout_name})
.populate('exercises')
.exec((err, workout) => {
if (err){
res.send(err);
} else {
res.send({ exercises: workout.exercises });
}
});
And then, on your client side, you can iterate the exercises array and access to the title of exercise

Building a simple news feed in node + Mongodb + Redis

My goal is to build a simple news feed in node.js with the help of mongodb and redis. It similar like twitter
So the scenario is pretty straight forward, once User A follow User B. Later on User's A News feed (Home page) will be shown User B's Activity like what he posted.
Schema for User
const UserSchema = new Schema({
email: { type: String, unique: true, lowercase: true},
});
const followSchema = new Schema(
{
user: { type: Schema.Types.ObjectId, required: true, ref: 'User' },
target: { type: Schema.Types.ObjectId, required: true, ref: 'User' },
});
Currently the design of my user's schema is pretty simple, when I follow another user, I will just create the Follow Schema Object
and there is another schema, which is post schema
/* This is similar like the Tweet */
var PostSchema = new Schema({
// Own by the user
creator: { type: Schema.Types.ObjectId, ref: 'User' }
body: String,
});
This schema is for user to post anything, similar like twitter posting.
Let say I have followed bunch of users
{
user: 'me',
target: 'draco'
},
{
user: 'me',
target: 'donald'
},
{
user: 'me',
target: 'joker'
}
and let say one of my followers, post something. How do i present it to my current news feed?
/* I'm following Joker */
app.post('/follow', (req, res, next) => {
let follow = new Follow();
follow.user = "me";
follow.target = "joker";
// Do i need to use redis to subscribe to him?
follow.save();
})
/* Joker posted something */
app.post('/tweet',(req, res, next) => {
let post = new Post();
post.creator = "joker";
post.body = "Hello my name is joker"
post.save();
// Do i need to publish it using redis so that I will get his activity?
});
Here's my attempt
app.get('/feed', function(req, res, next) {
// Where is the redis part?
User.findOne({ _id: req.user._id }, function(err, foundUser) {
// this is pretty much my attempt :(
})
})
When should I use redis to actually do the pub and sub? so that I could take the content of one of my followers and show it on my timeline?
I have built a social network which has a news feed, too. Here is how I did it.
Basically, you have 2 methods to built a newsfeed:
Fanout on write (push) method
Fanout on read (pull) method
Fanout on write
First, you will need another collection:
const Newsfeed = new mongoose.model('newsfeed', {
owner: {type: mongoose.Types.ObjectId, required: true},
post: {type: mongoose.Types.ObjectId, required: true}
});
When a user post something:
Get n follower
Push (fanout) this post to n follower
When a user get a feed:
Get from Newsfeed collection
Example:
router.post('/tweet', async (req, res, next) => {
let post = await Post.create({});
let follows = await Follow.find({target: req.user.id}).exec();
let newFeeds = follows.map(follow => {
return {
user: follow.user,
post: post.id
}
});
await Newsfeed.insertMany(newFeeds);
});
router.get('/feed', async (req, res, next) => {
let feeds = await Newsfeed.find({user: req.user.id}).exec();
});
Fanout on read
When a user post something:
Save
When a user get feed
Get n following
Get posts from n following
Example
router.post('/tweet', async (req, res, next) {
await Post.save({});
});
router.get('/feeds', async (req, res, next) {
let follows = await Follow.find({user: req.user.id}.exec();
let followings = follows.map(follow => follow.target);
let feeds = await Post.find({user: followings}).exec();
});
You don't need Redis or pub/sub to implement a newsfeed. However, in order to improve the performance, you may need Redis to implement some kind of cache for this.
For more information or advance technique, you may want to take a look at this.
User Schema :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const userSchema = new Schema({
name:{type:String},
email: { type: String, unique: true, lowercase: true},
},{
collection: 'User'
});
var User = module.exports = mongoose.model('User', userSchema);
Follow Schema :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var followSchema = new Schema(
{
follow_id: { type: Schema.Types.ObjectId, required: true, ref: 'User' },
leader_id: { type: Schema.Types.ObjectId, required: true, ref: 'User' }
},{
collection:'Follow'
});
var Follow = module.exports = mongoose.model('Follow', followSchema);
Post Schema :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var postSchema = new Schema({
creator: { type: Schema.Types.ObjectId, ref: 'User' }
body: {type: String , required:true},
created_at :{type:Date , default:Date.now}
},{
collection:'Post'
});
var Post = module.exports = mongoose.model('Post', postSchema);
Now Suppose you have 3 users in User collection :
{ _id: ObjectID('5a2ac68d1413751391111111') ,name:'John' , email:'john#gmail.com'}
{ _id: ObjectID('5a2ac68d1413751392222222') ,name:'Morgan' , email:'morgan#yahoo.com'}
{ _id: ObjectID('5a2ac68d1413751393333333') ,name:'Emily' , email:'emily#outlook.com'}
Now John Follows Morgan and Emily :
so in Follow collection there are two records
1) follow_id = John's ID and leader_id = Morgan's ID
2) follow_id = John's ID and leader_id = Emily's ID
{
_id: ObjectID('5a2ac68d141375139999999'),
follow_id : ObjectID('5a2ac68d1413751391111111'),
leader_id : ObjectID('5a2ac68d1413751392222222')
},
{
_id: ObjectID('5a2ac68d1413751393333333'),
follow_id : ObjectID('5a2ac68d1413751391111111'),
leader_id : ObjectID('5a2ac68d1413751393333333')
}
Now if you want to get User's Following :
app.get('/following/:user_id',function(req,res){
var userid=req.params.user_id;
Follow.find({follow_id:mongoose.mongo.ObjectID(userid)})
.populate('leader_id')
.exec(function(err,followings){
if(!err && followings){
return res.json({followings:followings});
}
});
});
for getting User's Followers :
app.get('/followers/:user_id',function(req,res){
var userid=req.params.user_id;
Follow.find({leader_id:mongoose.mongo.ObjectID(userid)})
.populate('follow_id')
.exec(function(err,followers){
if(!err && followers){
return res.json({followers:followers});
}
});
});
npm install redis
in your app.js :
var redis = require('redis');
var client = redis.createClient();
When one user create post :
app.post('/create_post',function(req,res){
var creator=new mongoose.mongo.ObjectID(req.body.creator);
var postbody=req.body.body;
async.waterfall([
function(callback){
// find followers of post creator
Follow.find({leader_id:creator})
.select({ "follow_id": 1,"leader_id":0,"_id": 0})
.exec(function(err,followers){
if(!err && followers){
callback(null,followers);
}
});
},
function(followers, callback){
// saving the post
var post=new Post({
creator: creator,
body: postbody
});
post.save(function(err,post){
if(!err && post){
// adding newly created post id to redis by key userid , value is postid
for(var i=0;i<followers.length;i++){
client.sadd([followers[i].follow_id,post.id]);
}
callback(null,post);
}
});
}
], function (err, result) {
if(!err && result){
return res.json({status:"success",message:"POST created"});
}
});
});
Now For Getting User NewsFeed :
1) first get array of postid from redis key of userid
2) loop through postid and get post from mongo
Function for get newsfeed by userid :
app.get('/newsfeed/:user_id',function(req,res){
var userid=req.params.user_id;
client.smembers(userid,function(err, reply) {
if(!err && reply){
console.log(reply);
if(reply.length>0){
var posts=[];
for(var i=0;i<reply.length;i++){
Post.findOne({_id:new mongoose.mongo.ObjectID(reply[i])}).populate('creator').exec(function(err,post){
posts.push(post);
});
}
return res.json({newsfeed:posts});
}else{
// No News Available in NewsFeed
}
}
});
});
Here we have use redis to store [userid,array of postids] for newsfeed ,
but if you dont want to use redis than just use below Newsfeed Model and store user_id and post_id for newly created post and then display it.
NewsFeed Schema :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var newsFeedSchema = new Schema({
user_id: {type: Schema.Types.ObjectId, refer:'User' , required:true}
post_id: {type: Schema.Types.ObjectId, refer:'Post' , required:true},
},{
collection:'NewsFeed'
});
var NewsFeed = module.exports = mongoose.model('NewsFeed', newsFeedSchema);
Helpful link for Redis : https://www.sitepoint.com/using-redis-node-js/
for Async : https://caolan.github.io/async/docs.html#

cant get data from database after multiple schema declared (mongoose + express + mongodb

I'm new to node.js and I am having problem accessing to the when multiple mongoose schema were declare.
//schema.js in model
var mongoose = require('mongoose');
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
//User Schema
var userSchema = new Schema({
id: ObjectId,
firstname: {type: String, require: true},
lastname: {type: String, require: true},
username: {type: String, unique: true, require: true},
password: {type: String, require: true},
role: {type: [String], require: true}
})
var User = mongoose.model('User', userSchema);
module.exports = User;
//Question Schema
var qnSchema = new Schema({
id: ObjectId,
question: {type: String, require: true},
module_id: {type: ObjectId, ref: 'Module'}
})
var Question = mongoose.model('Question', qnSchema);
module.exports = Question;
//Answer Schema
var ansSchema = new Schema({
id: ObjectId,
answer: String,
question: {type: ObjectId, ref: 'Question'}
})
var Answer = mongoose.model('Answer', ansSchema);
module.exports = Answer;
//Module Schema
var modSchema = new Schema({
id: ObjectId,
name: {type: String, require: true}
})
var Module = mongoose.model('Module', modSchema);
module.exports = Module;
//Role Schema
var roleSchema = new Schema({
id: ObjectId,
role: {type: String, require: true}
})
var Role = mongoose.model('Role', roleSchema);
module.exports = Role;
//index.js in controller
var mongoose = require('mongoose');
var User = require('../models/schema');
var db = mongoose.connect('mongodb://localhost/damai');
module.exports = function(app) {
app.get('/', function(req, res) {
if (typeof req.session.userid == 'undefined') {
res.render('login', { title: app.get('title') });
} else {
res.render('index', { title: app.get('title') });
}
});
app.post('/login', function(req, res) {
passwordVerification(req, res);
});
}
function passwordVerification(req, res)
{
var userid = req.param('userid');
var password = req.param('password');
User.findOne({'username': userid},{'password': 1}, function(err, cb)
{
console.log(cb);
if(cb!= null)
{
if (password == cb.password) {
req.session.userid = userid;
res.render('index', { title: app.get('title'), 'userid': userid });
} else {
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
}
else
{
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
});
}
When I only have the "User Schema" in my schema.js, the database call from method "passwordVerification()" from index.js will return me the relevant password that was retrieve from the database. However, when I start adding in other schema such as "Question Schema" in schema.js, the method "passwordVerification()" will always return null.
When exporting multiple models from a single file like you are in schema.js, you need to give each exported model its own exports field name.
For example, replace the multiple module.exports = ... lines in schema.js with this code at the end of the file that exports all models:
module.exports = {
User: User,
Question: Question,
Answer: Answer,
Module: Module,
Role: Role
};
And then in index.js you can access the models like so:
var models = require('./schema');
...
models.User.findOne(...

Resources