Mongoose Query Data in Express.js Node.js ,get the wrong result - node.js

The Problem is .. sometimes it shows up the wrong user on the screen (someone gets session of another one). but it's hardly happen and i think it only happen when there're some concurrent.
if anything in this code can make this behaviour happen , please suggest.
app.js -- this file has a schema and initiation of model and routes component
var userSchema = mongoose.Schema({
"_id": mongoose.Schema.Types.ObjectId,
"name": String,
"username":String,
"etc":String
});
userMongooseModel = mongoose.model('users',userSchema);
var sessionSchema = mongoose.Schema({
"userID": mongoose.Schema.Types.ObjectId,
"sessionID": String,
"expire":Number
});
sessionMongooseModel = mongoose.model('sessions',sessionSchema);
var UserModel = require(basePath+'/models/UserModel.js').UserModel;
userModel = new UserModel();
var user = require(basePath+'/routes/user');
routes/user.js -- this file is the detail about each route.
exports.editProfilePage = function(req,res){
var httpRes = res;
userModel.checkSession(req.cookies.session,function(res){
if(res.status=='success' && res.type=='photographer')
{
userModel.getByID(res.userID,{},function(resp){
httpRes.render(basePath+'/views/photographer-edit.html',{currentUser:res.user,user:resp.user,etc:'etc'});
});
}
else
{
//if not login or state != 0
httpRes.redirect(baseURL+'/photographerRedirect');
}
});
}
usermodel.js -- this file is to retrieve data from database
var mongoose = require('mongoose');
var ObjectId = mongoose.Types.ObjectId;
var request = require('request');
UserModel.prototype.checkSession = function(sessionID,callback){
sessionMongooseModel.findOne({sessionID:sessionID},function (err, user) {
if(err)
{
callback({status:'fail',errorMsg:'notFound'});
return;
}
if(user==null)
{
callback({status:'fail',errorMsg:'notFound'});
}
else
{
if(user.expire > Date.now())
{
userMongooseModel.findOne({_id:user.userID},{studioName:1,state:1,etc:1},function (err, user) {
if(err || user==null)
{
callback({status:'fail',errorMsg:'notFound'});
return;
}
if(user.type=='photographer' && user.state==0)
{
callback({status:'fail',errorMsg:'wrongUserState',userID:user._id,user:user,etc:1});
}
else
callback({status:'success',userID:user._id,user:user,type:user.type,etc:1});
});
}
else
{
callback({status:'fail',errorMsg:'notFound'});
}
}
});
}
UserModel.prototype.getByIDs = function(userIDs,options,callback){
userMongooseModel.find({_id:{$in:userIDs}},options,function (err, users) {
if(err){
callback({status:'fail',errorMsg:'UserModel.find'});
return;
}
callback({status:'success',users:users});
});
}
Thanks a lot !

(not sure if this is causing the problem, but it seems worth mentioning anyway)
Here, you're passing req.cookies.session, which is an object:
userModel.checkSession(req.cookies.session, ...);
But in checkSession, you're assuming it's an id:
UserModel.prototype.checkSession = function(sessionID, callback) {
sessionMongooseModel.findOne({sessionID:sessionID}, ...);
Just out of curiosity: any reason why you're not using one of the existing MongoDB-backed session stores for Express (like this one)?
Also, Mongoose has it's own way of adding class methods to models, using statics.

The answer is ... cache
Someone in the middle cache the content ,and it also send the wrong content to the wrong person so it seems like session was mixed
the way out is .. make server send flag no cache to the client
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');

Related

Best practice running queries in Node.js with MongoDB driver 3.6?

The official documentation of the Node.js Driver version 3.6 contains the following example for the .find() method:
const { MongoClient } = require("mongodb");
// Replace the uri string with your MongoDB deployment's connection string.
const uri = "mongodb+srv://<user>:<password>#<cluster-url>?w=majority";
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
const database = client.db("sample_mflix");
const collection = database.collection("movies");
// query for movies that have a runtime less than 15 minutes
const query = { runtime: { $lt: 15 } };
const options = {
// sort returned documents in ascending order by title (A->Z)
sort: { title: 1 },
// Include only the `title` and `imdb` fields in each returned document
projection: { _id: 0, title: 1, imdb: 1 },
};
const cursor = collection.find(query, options);
// print a message if no documents were found
if ((await cursor.count()) === 0) {
console.log("No documents found!");
}
await cursor.forEach(console.dir);
} finally {
await client.close();
}
}
To me this somewhat implies that I would have to create a new connection for each DB request I make.
Is this correct? If not, then what is the best practise to keep the connection alive for various routes?
You can use mongoose to set a connection with your database.
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true});
then you need to define your models which you will use to communicate with your DB in your routes.
const MyModel = mongoose.model('Test', new Schema({ name: String }));
MyModel.findOne(function(error, result) { /* ... */ });
https://mongoosejs.com/docs/connections.html
It's 2022 and I stumbled upon your post because I've been running into the same issue. All the tutorials and guides I've found so far have setups that require reconnecting in order to do anything with the Database.
I found one solution from someone on github, that creates a class to create, save and check if a client connection exist. So, it only recreates a client connection if it doesn't already exist.
const MongoClient = require('mongodb').MongoClient
class MDB {
static async getClient() {
if (this.client) {
return this.client
}
this.client = await MongoClient.connect(this.url);
return this.client
}
}
MDB.url='<your_connection_url>'
app.get('/yourroute', async (req, res) => {
try {
const client = await MDB.getClient()
const db = client.db('your_db')
const collection = db.collection('your_collection');
const results = await collection.find({}).toArray();
res.json(results)
} catch (error) {
console.log('error:', error);
}
})

Sequelize create belongTo instance with reference

I'm using Sequelize for my new NodeJs project
I defined two models: BusinessUnit and Store with this association: Store.belongsTo(BusinessUnit);
module.test_data_insertion = function() {
models.BusinessUnit.findOne({
where: {
BUID: "001"
}
}).then(element => {
fs.readdirSync(dir).forEach(function(file) {
var contents = fs.readFileSync(dir + file);
var jsonContent = JSON.parse(contents);
models.Store.create({
StoreId: jsonContent.StoreId,
StoreName: jsonContent.StoreName,
businessUnitId: element.id
});
});
});
};
I don't find to right way to reference the element in my Store, I would like something like this where I don't have to reference an id field directly
module.test_data_insertion = function() {
models.BusinessUnit.findOne({
where: {
BUID: "001"
}
}).then(element => {
fs.readdirSync(dir).forEach(function(file) {
var contents = fs.readFileSync(dir + file);
var jsonContent = JSON.parse(contents);
models.Store.create({
StoreId: jsonContent.StoreId,
StoreName: jsonContent.StoreName,
businessUnit: element
});
});
});
};
It should be simple but I don't see it. Thanks
Assuming your association are setup correctly, you are looking for something like this:
module.test_data_insertion = function() {
models.BusinessUnit.findOne({
where: {
BUID: "001"
}
}).then(element => {
fs.readdirSync(dir).forEach(function(file) {
var contents = fs.readFileSync(dir + file);
var jsonContent = JSON.parse(contents);
element.setStore({
StoreId: jsonContent.StoreId,
StoreName: jsonContent.StoreName,
});
});
});
};
please read belongsTo from doc which enables a set method,
However please note if this is a one to many relationship(one business unit with many stores) you may need to switch to belongsToMany it has add method. because setStore would override previous set.
Also, i'm not sure if any of those method would work inside .forEach correctly since they are promise, you may need to switch to a traditional for loop.

Mongoose.create creating document but none of my data

I'm learning to use the mean stack and trying to build a url shortener. I've got a module that takes the req.params.UserUrl checks and makes sure it's a valid url then creates a random number that I want to use as the short route. I can't seem to find a way to save the random number so that I can check their next url request against it. After a google search it seemed maybe the most effecient way would be to save an object in the database with the long_url and the short_url:randomNumber. My code doesn't throw any errors but when I check my heroku database it has a new entry but only has the _id and __v that mLabs generates itself. Can someone tell me where I'm going wrong.
Route File
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var URLShortener = require(process.cwd()+'/public/Modules/urlShortener.module.js');
var ShortURL = require('../models/shortUrl.js');
router.get('/', function(req, res) {
res.render('index', { title: 'FreeCodeCamp Projects' });
});
router.get('/urlShortener', function(req, res){
res.render('freecodecamp/urlShortener', { title: 'Url Shortener Site'});
});
router.get('/urlShortener/:userUrl', function(req, res){
if(URLShortener.checkValidUrl(req.params.userUrl))
{
var UserUrl = req.params.userUrl;
var randNbr = URLShortener.assignRanNbr();
ShortURL.create(URLShortener.createUrlObj(UserUrl, randNbr), function (err, smallUrl) {
if (err) return console.log(err);
else res.json(smallUrl);
});
}
else
{
res.send('Invalid url');
}
});
router.get('/:short', function(req, res){
if(randNbr == req.params.short)
{
res.redirect(userUrl);
}
else
{
res.send('Not the correct shortcut');
}
});
module.exports = router;
Url Schema
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var shortUrlSchema = new Schema({
long_id:String,
short_id:Number
}, {collection: 'shortUrl'});
module.exports = mongoose.model('shortUrl', shortUrlSchema);
urlShortener Module
'use strict'
module.exports.checkValidUrl = function(url){
var pattern = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)/);
return pattern.test(url);
}
module.exports.assignRanNbr = function(){
var randNbr = Math.floor(Math.random() * (9999 - 1 + 1)) + 1;
return randNbr;
}
module.exports.createUrlObj = function(url, num){
var urlObj = {};
urlObj.original_url = url;
urlObj.short_url = 'https://rawlejuglal-me-rawlejuglal-1.c9users.io/freecodecamp/'+num;
return urlObj;
}
Your createUrlObj method is returning an object with the properties original_url and short_url, but your shortUrlSchema properties are long_id and short_id. The property names in your create method need to match your schema. The property value types must also match your schema types (currently short_url is a string and short_id is a number). I think what you really want is for your createUrlObj method to be
module.exports.createUrlObj = function(url, num){
var urlObj = {};
urlObj.long_url = url;
urlObj.short_id = num;
return urlObj;
}
and your schema to be
var shortUrlSchema = new mongoose.Schema({
long_url: String,
short_id: Number
}, {collection: 'shortUrl'});
Additionally, your '/:short' route should have a call to the database since the randNbr and userUrl variables are not defined in that route.
router.get('/:short', function(req, res){
ShortUrl.findOne({short_id: req.params.short}, function(err, shortUrl){
if(err) res.send('Invalid Url');
res.redirect(shortUrl.long_url)
})
});

RESTful CRUD for Angular and Express $resource

I have my JSON querying and creating correctly. I'm a bit stuck on how to remove items from the server. They are being removed in angular but I can't seem to get the connection right for removing them on the server.
My server.js:
var hcController = require('./server/controllers/services-controller.js')
//REST API
app.get('/api/hc', hcController.list);
app.post('/api/hc', hcController.create);
app.delete('/api/hc:_id', hcController.delete);
My server-side model
var mongoose = require('mongoose');
module.exports = mongoose.model('HealingCenterData',{
title: String,
shortname: String,
summary: String,
description: String
});
My server-side controller
var Hc = require('../models/healingcenter-model.js')
module.exports.create = function (req, res) {
var hc = new Hc(req.body);
hc.save(function (err, result){
res.json(result);
});
}
module.exports.list = function (req,res) {
Hc.find({}, function (err, results){
res.json(results);
});
}
module.exports.delete = function (req, res) {
???????
});
}
My angular service:
app.factory("HC", ["$resource", function($resource) {
return {
API: $resource('/api/hc/:id')
}
}]);
My angular controller:
app.controller('servicesController', ['$scope', 'HC','$resource', function ($scope, HC, $resource) {
HC.API.query(function(results) {
$scope.services = results;
});
$scope.createService = function() {
var service = new HC.API();
service.title = $scope.serviceTitle;
service.shortname = $scope.serviceShortname;
service.summary = $scope.serviceSummary;
service.description = $scope.serviceDescription;
service.$save(function(result){
$scope.services.push(result);
$scope.serviceTitle = '';
$scope.serviceShortname = '';
$scope.serviceSummary = '';
$scope.serviceDescription = '';
});
}
$scope.removeItem = function(index){
$scope.services.splice(index, 1);
}
}]);
My JSON structure
{ "_id" : ObjectId("53bea9366a03a66c2dad68bb"), "title" : "Auto Clinic", "shortname" : "auto_clinic", "summary" : "Volunteers evaluate car problems and make minor repairs. Labor is free, and the car owner pays for any needed parts. Oil changes are performed at a reduced cost. All services are performed on Saturdays.", "description" : "No additional information yet.", "__v" : 0 }
On the server side try (I'm assuming you are using moongose) :
exports.delete = function(req,res){
if(req.params.id !==null || req.params.id!==undefined){
Hc.remove({_id:req.params.id},function(err){
res.send(200);
});
}
};
on the client side:
angular controller:
var endPoint = $resource('/api/hc/:id', {id:'#tId'});
$scope.removeItem = function(id){
var ep = new endPoint({tId:id});
ep.$delete(function(res){
//TODO: update local array in scope
});
};
EDIT:
you can just use the resource directly in the controller or just the service as you have done in your case, that's totally fine.

Node.js Express PUT Functionality - Saving data

I am setting up a server with Node and Express for the first time and am having trouble saving the response I am retrieving in my PUT call. This is a survey - I need to update the model with the "responded" object entered in the survey.
I do see the correct response outputting in the console but receive "Object [object Object],[object Object],[object Object],[object Object],[object Object] has no method 'findById'" from my "save" function.
Thank you in advance.
kitty-questions.json
[
{
"id": "favorite-food",
"number": "1",
"url": "favorite-food",
"name": "Favorite Food",
"question": "Which of the following best describes your kitty's palatte?",
"responded" : "default response",
"query": "Which of the following best describes your kitty's palatte?",
"answers": {
"Grumpy" : "Fresh Water Salmon, no bones, served on china",
"Hipster" : "Nothing - trying to fit into newer, tighter jeans",
"Pudge" : "Anything and everything my owner is eating",
"Bub" : "Mice",
"Meow" : "Roaches"
}
},
{
"id": "favorite-band",
"number": "2",
"url": "favorite-band",
"name": "Favorite Band",
"question": "Your kitty claws at you desperatly when it wants to listen to:",
"responded" : "default response",
"query": "Which of the following best describes your kitty's palatte?",
"answers": {
"Bub" : "Country",
"Grumpy" : "Mozart. Popular music is for the plebs.",
"Pudge" : "z100",
"Meow" : "Very heavy metal",
"Hipster" : "something long winded"
}
}
Server.js
var express = require('express'),
http = require('http'),
questions = require('./data/kitty-questions');
var app = express()
.use(express.bodyParser())
.use(express.static('public'));
app.get('/questions', function (req, res) {
res.json(questions);
});
app.post('/questions', function (req, res) {
var matches = questions.filter(function (question) {
return question.url === req.body.url;
});
if (matches.length > 0) {
res.json(409, {status: 'question already exists'});
} else {
req.body.id = req.body.url;
questions.push(req.body);
res.json(req.body);
}
});
app.put('/questions/:question_name', function (req, res) {
var matches = questions.filter(function (question) {
return question.url === req.params.question_name;
});
var catResponse = req.body.responded;
console.log(JSON.stringify(catResponse));
return questions.findById(req.params.question_name, function (err, question) {
question.catResponse = req.body.responded;
return question.save(function (err) {
if (!err) {
console.log("updated");
} else {
console.log(err);
}
return res.send(question);
});
});
});
app.get('/questions/:question_name', function (req, res) {
var matches = questions.filter(function (question) {
return question.url === req.params.question_name;
});
if (matches.length > 0) {
res.json(matches[0]);
} else {
res.json(404, {status: 'invalid survey question'});
}
});
app.delete('/questions/:question_name', function (req, res) {
var found = false;
items.forEach(function (question, index) {
if (question.url === req.params.question_name) {
found = index;
}
});
if (found) {
items.splice(found, 1);
res.json(200, {status: 'deleted'});
} else {
res.json(404, {status: 'invalid survey question deletion'});
}
});
app.get('/*', function (req, res) {
res.json(404, {status: 'not found'});
});
http.createServer(app).listen(3000, function () {
console.log("Server ready at http://localhost:3000");
});
STRING FROM THE TERMINAL AFTER MAKING PUT CALL:
Server ready at http://localhost:3000
TypeError: Object [{"id":"favorite-food","number":"1","url":"favorite-food","name":"Favorite Food","question":"Which of the following best describes your kitty's palatte?","responded":"default response","query":"Which of the following best describes your kitty's palatte?","answers":{"Grumpy":"Fresh Water Salmon, no bones, served on china","Hipster":"Nothing - trying to fit into newer, tighter jeans","Pudge":"Anything and everything my owner is eating","Bub":"Mice","Meow":"Roaches"}},{"id":"favorite-band","number":"2","url":"favorite-band","name":"Favorite Band","question":"Your kitty claws at you desperatly when it wants to listen to:","responded":"default response","query":"Which of the following best describes your kitty's palatte?","answers":{"Bub":"Country","Grumpy":"Mozart. Popular music is for the plebs.","Pudge":"z100","Meow":"Very heavy metal","Hipster":"something long winded"}},{"id":"favorite-hideout","number":"3","url":"favorite-hideout","name":"Favorite Hideout","question":"You are most likely to find your beast perched here:","responded":"","answers":{"Bub":"On your shoulder","Grumpy":"Alone. Anywhere, just alone.","Pudge":"In the fridge","Meow":"Herding other cats","Hipster":"Outside, smoking."}},{"id":"favorite-friends","number":"4","url":"favorite-friends","name":"Favorite Friends","question":"Your kitty generally gets along with:","responded":"","answers":{"Bub":"Other cats","Grumpy":"No one.","Pudge":"Humans, animals, whoever.","Meow":"Obedient animals","Hipster":"dogs"}},{"id":"favorite-celebrity","number":"5","url":"favorite-celebrity","name":"Favorite Celebrity","question":"Your feline cannot get enough of this red carpet walker:","responded":"","answers":{"Bub":"Meg Ryan","Grumpy":"Jack Nicholson","Pudge":"John Candy","Meow":"Does General McArthur count?","Hipster":"Zooey Deschanel"}}] has no method 'update'
3/19 UPDATE:
app.put('/questions/:question_name', function (req, res) {
var question = questions.filter(function (question) {
return question.url === req.params.question_name;
});
var defaultResponse = question[0].responded;
res.json(defaultResponse);
var catResponse = req.body.responded;
questions.update({id: req.params.question_name}, function (err, question) {
question.catResponse = catResponse;
question.save(function (err) {
if (!err) {
res.send(catResponse);
} else {
res.send(400); //or something
}
});
});
});
There are a lot of unnecessary returns going on here, and at the very least, they make the code confusing to read.
Removing some stuff and ignoring the matches variable, since that isn't used in the PUT itself, something like this may be more what you're looking for:
app.put('/questions/:question_name', function (req, res) {
var catResponse = req.body.responded;
questions.update({id: req.params.question_name}, function (err, question) {
question.catResponse = catResponse;
question.save(function (err) {
if (!err) {
res.send(question);
} else {
res.send(400); //or something
}
});
});
});
*EDIT*
I assumed that questions = require('./data/kitty-questions'); was your mongoose model. You need questions to be a mongoose model for update to work.
Like:
var mongoose = require('mongoose')
, Questions = mongoose.model('Question')
Then your questions model file probably looks like:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
QuestionSchema = new Schema({
//keys and stuff in here
});
mongoose.model('Question', QuestionSchema);

Resources