how to fix "model.findByIdAndUpdate' not updating documents in mongodb 4.0? - mongodb

I'm learning expressjs and i'm trying to update a document in my mongodb database by id and using PUT to specify a route, after entering this command in the terminal:
curl -X PUT --data "name =James&age = 20&nationality=American"http://localhost:3000/people/5d3ba2a863ba682d70242131
It prints out the document but nothing has been updated
I have used {new:true} as recommended against the default setting ({new:false}) however nothing has changed. without specifying any route it works
e.g
Person.findOneAndUpdate({name:'deean'},{age:34},function(err,response){
console.log(response);
});
the above code works
but this doesn't:
app.put('/people/:id', function(req, res){
Person.findByIdAndUpdate(req.params.id, req.body, {new: true} ,function(err, response){
if(err)
res.json({message:"Error in updating person with id" + req.params.id});
res.json(response);
});
});
app.listen(3000);
the original document i am trying to change is
{ _id: 5d3ba2a863ba682d70242131,
name: 'deean ajashi',
age: 34,
nationality: 'indian',
__v: 0 } ]
this is the output i'm getting on the terminal
C:\Users\Diola>curl -X PUT --data "name = James&age = 20&nationality = American" http://localhost:3000/people/5d3ba2a863ba682d70242131
{"_id":"5d3ba2a863ba682d70242131","name":"dean ajashi","age":34,"nationality":"indian","__v":0}
C:\Users\Diola>
The format i'm using is from Tutorialspointclick to check out page on Tutorialspoint
edit: i think this is what you mean by model and router file though i'm not sure
var express = require('express');
var multer = require("multer");
var upload = multer();
var app = express();
app.set('view engine', 'pug');
app.set('views', './views');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(upload.array());
app.use(express.static('public'));
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydb', { useNewUrlParser: true });
var personSchema = mongoose.Schema({
name: String,
age: Number,
nationality: String
});
var Person = mongoose.model("Person", personSchema);
app.get('/person', function(req, res){
res.render('person');
});
app.post('/person', function(req, res){
var personInfo = req.body;
console.log('recived your request');
console.log(req.body);
if(!personInfo.name || !personInfo.age || !personInfo.nationality){
res.render('show_message', {
message: "Sorry, you provided worng info", type: "error"});
} else {
var newPerson = new Person({
name: personInfo.name,
age: personInfo.age,
nationality: personInfo.nationality
});
newPerson.save(function(err, Person){
if(err)
res.render('show_message', {message: "Database error", type: "error"});
else
res.render('show_message', {
message: "New person added", type: "success", person: personInfo});
});
}
});

when you pass {new: true} it returns the updated document (Vs) old document if it's false it has nothing to do with update operation, Can you give us your model and router file, meanwhile - try below code & check if you're able to get request by printing req.params.id and req.body :
app.put('/people/:id', function(req, res){
Person.findByIdAndUpdate(req.params.id, {$set:req.body}, {new: true} ,function(err, response){
if(err) res.json({message: "Error in deleting record id " + req.params.id});
else res.json(response);
});
});
app.listen(3000);

Related

Get all documents from an authenticated user (relation OneToMany)

I am learning to use mongoDB AND ExpressJS by building a Rest API that I would use with ReactJS.
I have always chosen MySQL for the management of my database, but the mongoDB database is not relational and it is still difficult for me to understand.
An example of what I want to do
Let's say that I have created a blog and want to get all the articles from a user logged in with an account.
All these operations are managed with a REST API and MongoDB.
How to create a OneToMany relationship between articles and a user.
With MySQL I just had to specify a user_id key for each article in an article table.
But with mongoDB how to create this and especially for a user who is logged in with an account, so that only a logged in user can view his articles.
EDIT
I have tried something, it works but I don't know if it's the right approach.
Context:
I made a REST API with NodeJS and ExpressJS.
The API will allow a user to organize their applications to facilitate the search for a job.
A user must create an account and log in to take advantage of all of the application's features, so no information is publicly available.
For registration and authentication of a user, I use PassportJS, mongoConnect and ExpressSession
To start, the User model of mongoDB
const userSchema = mongoose.Schema({
name: {
type:String
},
email: {
type:String,
required:true,
unique:true
},
email_is_verified: {
type:Boolean,
default:false
},
password: {
type:String,
},
referral_code : {
type:String,
default: function() {
let hash = 0;
for(let i=0; i < this.email.length; i++){
hash = this.email.charCodeAt(i) + ((hash << 5) - hash);
}
let res = (hash & 0x00ffffff).toString(16).toUpperCase();
return "00000".substring(0, 6 - res.length) + res;
}
},
referred_by : {
type: String,
default:null
},
third_party_auth: [ThirdPartyProviderSchema],
date: {
type:Date,
default: Date.now
}
},
{ strict: false }
);
module.exports = mongoose.model('Users', userSchema);
The Apply model represents an apply for a job, for now there is only the title.
To create the OneToMany relationship, I add a User field which refers to my User model
Function to retrieve all applies, so I retrieve the user id of the session.
const applySchema = mongoose.Schema({
title: { type:String, required:true },
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
})
module.exports = mongoose.model('Apply', applySchema);
I created a controller for the management of a user's applies
exports.getAllApplies = (req, res, next) => {
res.locals.currentUser = req.user;
const userId = res.locals.currentUser.id
Apply.find({ user:userId })
.then(applies => res.status(200).json({ message:'success',
applies:applies }))
.catch(error => res.status(400).json({ error:error, message: 'Failed'}))
}
Function allowing to consult an apply
exports.getOneApply = (req, res, next) => {
res.locals.currentUser = req.user;
const userId = res.locals.currentUser.id
Apply.findOne({ _id:req.params.id, user:userId })
.then(apply => res.status(200).json({ message: `Apply with id
${apply._id} success`, apply:apply}))
.catch(error => res.status(500).json({ error:error, message:'Failed'}))
}
The routes of my api, I add an auth middleware to allow requests only for a user with a token
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
const applyCtrl = require('../controllers/apply');
router.get('/', auth, applyCtrl.getAllApplies);
router.get('/:id', auth, applyCtrl.getOneApply);
module.exports = router;
I apologize for the length of the post, if you have any questions, I would be happy to answer them.
Thank you in advance for your help and your answers.

JSON formatting when saving using Mongoose is not bringing back the expected result

I have a code block in my Mongoose controller which attempts to find both Projects and Levels:
exports.landing = (req, res, next) => {
console.log(req.params.projectid);
Project.findById(req.params.projectid, (err, project) => {
if (err) return res.status(500).send(err);
//find the level based on the projectid
Level.find({'projectid': req.params.projectid}, (err, level) => {
if (err) return res.status(500).send(err);
//find the level based on the projectid
res.json({
success: true,
message: 'got',
level: level.leveltempnodes
});
//res.render(path + 'project', {project: project, moment: moment, level: level});
});
});
};
Within the res.json section, If I just use 'level' without the dot notation, all the results come back as expected. When I try and get the 'levelnodes' entry, nothing comes back. The only thing I see differently with the level document compared to the other documents is that the JSON result includes a '[':
{"success":true,"message":"got","level":{"_id":"5b4205ea5b44e146b5978175" ...
The above works fine. But I am not able to use dot syntax on the below result:
{"success":true,"message":"got","level":[{"_id":"5b4202fc94855d56204c8bb7"
I am saving the level document like this:
var data = {
levelname: levelname,
leveltempnodes: leveltempnodes,
projectid: projectid};
var level = new Level(data);
level.save(function (err) {
if (err) return handleError(err);
})
My error is nothing is coming back at all:
{"success":true,"message":"got"}
Schema:
const mongoose = require('mongoose');
const LevelSchema = mongoose.Schema({
levelname: String,
leveltempnodes: String,
projectid: String
});
module.exports = mongoose.model('Level', LevelSchema);
Data is being stored on the DB without issue. I am adding it via Ajax:
var p = {
projectname : $("#projectname").val(),
levelname : 'Root',
leveltempnodes : '{"class":"go.GraphLinksModel","nodeKeyProperty":"id","nodeDataArray":[{"id":1,"loc":"226 226","text":"sensor"},{"text":"perception","loc":"426 225.99999999999997","id":-2},{"text":"planning","loc":"626 225.99999999999997","id":-3},{"text":"gate","loc":"826 225.99999999999997","id":-4}],"linkDataArray":[{"from":1,"to":-2,"text":"msg","points":[296.7874157629703,237.73538061447854,340.03133208792605,227.76937481449303,383.33478829426565,227.0952320784595,426.7981545990892,236.1401244399739]},{"from":-2,"to":-3,"text":"msg","points":[523.225709890083,236.1861908341044,558.0349502392196,229.00680324793404,592.1479459982006,228.54232080927673,626.6289592123036,236.76409981273324]},{"from":-3,"to":-4,"text":"msg","points":[709.6483081744094,237.23795381070627,748.7663709980919,229.48139598538538,787.383185499046,229.48139598538538,826.1210439041331,238.64104211943584]}]}',
}
if(p.projectname == ''){
console.log('e');
}else{
$.ajax({
type: 'POST',
contentType : "application/json",
url: 'api/project/save',
data : JSON.stringify(p),
success: function(res) {
window.location.replace("/project/"+res.id);
}
});

Getting "TypeError: db.createList is not a function"

I am currently doing a React, Express, Massivejs, postgreSql app. I am getting the error "TypeError: db.createList is not a function" anytime I'm trying to hit my post endpoint. I'm not sure how to remedy it since it looks correct.
My file structure:
My server file looks like this:
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var massive = require("massive");
var connectionString = 'postgress://LonnieMcGill#localhost/todo';
var massiveInstance = massive.connectSync({connectionString : connectionString})
var config = require('./config.js');
var app = module.exports = express();
app.set('db', massiveInstance);
var listCtrl = require('./controller/listCtrl.js');
// **************** Middleware ****************
app.use(express.static(__dirname + './../public'));
app.use(bodyParser.json());
// ****************** Endpoints ***************
app.post('/api/add/list', listCtrl.createList);
app.get('/api/get/list', listCtrl.createList);
app.get('*', function(req, res) {
res.sendFile('index.html', { root: './public'});
})
app.listen(config.port, function() { console.log('Server initiated on port', config.port); });
My controller looks like this:
var app = require('../server.js');
var db = app.get('db');
module.exports = {
createList: function(req, res, next) {
console.log('db'my);
db.createList([req.body.name], function(err, res) {
res.status(200).send('List created');
})
},
readList: function(req, res) {
db.readList(function(err, res) {
if (err) {
console.log("readList failed");
} else {
console.log("readList working " + req.body, req.params);
}
})
}
}
My createList.sql file looks like this:
INSERT INTO list (
name
)
VALUES (
$1
);
The documentation clarifies this issue. By default, the "db" folder should stay in the root directory of your project, and not where the scripts consuming the database are (in this case, "server/").
You must either move "db" to the root directory of your project (so as to be alongside "server", "public", etc.), or configure the scripts property to point to that location:
var massiveInstance = massive.connectSync({
scripts: "server/db",
connectionString
})

React + Sails + Socket.io

This is quite a broad question, however I currently have a Sails API server and a React Front-end (Standalone).
Note: The React Front-End is NOT part of Sails
I'm trying to get to grips with sockets, so I figured I would start simple. I want to achieve the following:
User visits my website (React)
React opens a socket and connects to Sails
Sails streams the data from within a function/model
React updates when new data is added to the model
I semi understand how this works using Express and React, however I cannot get my head around how Sails implements their version of WebSockets on top of Sockets.io.
What I've done is install the sockets.io-client within React, and then trying to use sails.sockets inside Sails.
This is what I currently have:
React Component NB: I don't think this is correct at all
componentDidMount =()=> {
this.getSessionData();
UserStore.listen(this.getSessionData);
Socket.emit('/listSessions', function(data){
console.log(data);
})
}
Sails Function (listSessions)
listSessions: function(req, res) {
Session.find({ where: {visible: true}, sort: 'createdAt DESC'},
function(err, sessions){
if(req.isSocket){
Session.watch(req.socket);
console.log('User subscribed to ' + req.socket.id);
}
if(err) return res.json(500, {
error: err,
message: 'Something went wrong when finding trades'
});
return res.json(200, {
sessions: sessions,
});
})
},
Sails Function (createSession) Trying to use publishCreate to use in conjunction with Session.watch in the above function
createSession: function(req, res){
var token = jwt.sign({
expiresIn: 30,
}, 'overwatch');
Session.create({
username: req.body.username,
platform: req.body.platform,
lookingFor: req.body.lookingFor,
microphone: req.body.microphone,
gameMode: req.body.gameMode,
comments: req.body.comments,
avatar: null,
level: null,
hash: token,
competitiveRank: null,
region: req.body.region,
visible: true,
}).exec(function(err, created){
Session.publishCreate(created);
if(err) {
console.log(err);
return res.send({
error: err,
message: 'Something went wrong when adding a session',
code: 91
})
}
if(req.isSocket){
Session.watch(req.socket);
console.log('User subscribed to ' + req.socket.id);
}
return res.send({
session: created,
code: 00,
})
});
},
Both of the Sails functions are called using POST/GET.
I'm completely stumped as where to go with this, and it seems to documentation or explanation on how to get this working is limited. All the Sails documentation on Sockets seems to relate to using Sails as a front-end and server
OK so I managed to solve this:
Simply put:
Within React, I had to include https://github.com/balderdashy/sails.io.js/tree/master
Then within my React component I did:
componentDidMount =()=> {
io.socket.get('/listSessions',(resData, jwres) => {
console.log('test');
this.setState({
sessions: resData.sessions,
loaded: true,
})
})
io.socket.on('session', (event) => {
if(event.verb == 'created') {
let sessions = this.state.sessions;
sessions.push(event.data);
this.setState({
sessions: sessions
})
} else {
console.log('nah');
}
});
}
This makes a virtual get request to Sails using Socket.io, and sets the response in state. It also watches for updates to the 'session' connection and updates the state with these updates meaning I can update a list in real time
Within my Sails controller I have:
listSessions: function(req, res) {
if(req.isSocket){
Session.find({ where: {visible: true}, sort: 'createdAt DESC'},
function(err, sessions){
Session.watch(req.socket);
if(err) return res.json(500, {
error: err,
message: 'Something went wrong when finding trades'
});
return res.json(200, {
sessions: sessions,
});
})
}
},
The Session.watch line listens for updates via publishCreate on the model which is found in my model as follows:
afterCreate: function(message, next) {
Session.publishCreate(message);
next();
},
Adding to answer by #K20GH , add the following to my "index.js" in React to help get sails.io.js from the CDN :
const fetchJsFromCDN = (src, externals = []) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.setAttribute('src', src);
script.addEventListener('load', () => {
resolve(
externals.map(key => {
const ext = window[key];
typeof ext === 'undefined' &&
console.warn(`No external named '${key}' in window`);
return ext;
})
);
});
script.addEventListener('error', reject);
document.body.appendChild(script);
});
};
fetchJsFromCDN(
'https://cdnjs.cloudflare.com/ajax/libs/sails.io.js/1.0.1/sails.io.min.js',
['io']
).then(([io]) => {
if (process.env.NODE_ENV === 'development') {
io.sails.url = 'http://localhost:1337';
}
});
Once you have this, you'll be able to use the HTTP type GET, PUT, POST and DELETE methods. So here you can do:
componentDidMount =()=> {
io.socket.get('/listSessions',(resData, jwres) => {
console.log('test');
this.setState({
sessions: resData.sessions,
loaded: true,
})
})
io.socket.on('session', (event) => {
if(event.verb == 'created') {
let sessions = this.state.sessions;
sessions.push(event.data);
this.setState({
sessions: sessions
})
} else {
console.log('Not created session');
}
});
}
And you can do the required setup in sails for the models of sessions as suggested above

How do I Build A .json Endpoint with a Sequelize Query?

Struggling to get my head around this for a week and a half, I was wondering how to get a .json endpoint that is from a query from the Sequelize ORM. Currently it logs a 404 error "GET /api/users 404 3ms". As you may have heard the documentation for Sequelize is pretty limited and I've been searching github repo after tutorial and none have worked thus far, so I'd thought I'd ask here.
A small excerpt (code on https://github.com/NatuMyers/A.M.E.N.SQL-Stack):
// VARS -----------------------------
var express = require('express')
, bodyParser = require('body-parser')
, errorHandler = require('errorhandler')
, methodOverride = require('method-override')
, morgan = require('morgan')
, http = require('http')
, path = require('path')
, db = require('./models')
var router = require('express').Router();
var app = express()
// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(morgan('dev'))
app.use(bodyParser())
app.use(methodOverride())
app.use(express.static(path.join(__dirname, 'public')))
// SEQUELIZE MODELS
var userVar = require('./models/user');
// dev only
if ('development' === app.get('env')) {
app.use(errorHandler())
}
// Make db, and make it listen
db
.sequelize
.sync()
.complete(function(err) {
if (err) {
throw err
} else {
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'))
})
}
})
// HTTP GET endpoints
module.exports = function() {
router.get('/', function(req, res, next){
res.json({ message: 'This works at localhost:3000/api but getting a list of users is a pain :(' });
});
// question
router.get('/users', function(req, res, next){
res.json(/* I need to make sequelize send a part of the User db here. */);
});
return router;
};
I moved on from this by using Epilogue.js (in a vanilla way).
I added models INLINE with Sequelize (I wasted lots of time trying to import models), then add any middle ware and create the restful api based on the syntax below.
// 1. ADD SEQUELIZE MODELS ---- ---- ---- ----
var database = new Sequelize('raptroopdb', 'root', 'strongpassword');
var Employee = database.define('Employee', {
name: Sequelize.STRING,
hireDate: Sequelize.DATE
});
// Add Account model with foreign key constraint to Employee
var Account = database.define('Account', {
name: Sequelize.STRING,
managerId: {
type: Sequelize.INTEGER,
references: {
// This is a reference to model Employee
model: Employee,
// This is the column name of the referenced model
key: 'id',
}
}
});
// 2. ROOM FOR MIDDLEWARE to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('In server.js');
// make sure we go to the next routes and don't stop here
next();
});
// Initialize epilogue
epilogue.initialize({
app: app,
sequelize: database
});
app.use(express.static(__dirname + "/public"));
app.get('/', function(req, res) {
res.redirect('/public/index.html');
});
// 3. Create REST resource
var employeeResource = epilogue.resource({
model: Employee,
endpoints: ['/api/employees', '/api/employees/:id']
});
var acctResource = epilogue.resource({
model: Account,
endpoints: ['/api/accounts', '/api/accounts/:id']
});
// Create database and listen
database
.sync({
force: false
})
.then(function() {
app.listen(port, function() {
console.log('listening at %s', port);
});
});