Unable to update an object inside MongoDB collection using HTTP Put? - javascript

I am new to AngularJS and I was trying to update my MongoDB Database. I am having an issue when I am trying to update an object inside my collection. The following is my attempt at trying to do so:
//listviewFactory is already injected and returns an event object
//I call $scope.put when clicking (ng-click) on a button
$scope.event = listviewFactory.getEvent();
$scope.put = function(event){
var currentUser = {};
if($cookieStore.get('token')) {
currentUser = User.get();
}
event.attendees.push(currentUser);
$http.post('/api/events/' + event._id, event).success(function(data){
for(var i = 0; i < event.attendees.length; i++){
console.log("Attendees: ", event.attendees[i]);
}
$location.path('/');
});
};
I'm just unsure of why my code isn't working. When I do the $http put request, my function is successful and proceeds to perform the console.log. When I print out the attendees array, I saw that the currentUser object is indeed appended to my event.attendees array. However, when I check my database using the Mongo shell, My attendees array is not updated and remains blank. Any ideas on why or where I may be wrong at? Below is also my server side code in how I am routing my application and specifying how to store the information in MongoDB.
module.exports = function(app) {
app.use('/api/events', require('./api/event'));
...
}
module.exports = mongoose.model('Event', EventSchema);
var express = require('express');
var controller = require('./event.controller');
var router = express.Router();
router.get('/', controller.index);
router.put('/:id', controller.update);
// Updates an existing event in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Event.findById(req.params.id, function (err, event) {
if (err) { return handleError(err); }
if(!event) { return res.send(404); }
var updated = _.merge(event, req.body);
updated.save(function (err) {
if (err) { return handleError(err); }
return res.json(200, event);
});
});
};
EDIT: When I console.log currentUser:
Current User:
Resource {$promise: Object, $resolved: false, $get: function, $save: function, $query: function…}
$promise: Object
$resolved: true
__v: 0
_id: "53dd72fb5a24aa781a3cbde8"
email: "test#test.com"
name: "Test User"
provider: "local"
role: "user"
EDIT: Mongoose schema:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var EventSchema = new Schema({
startDate: Date,
endDate: Date,
eventLocation: String,
eventName: String,
attendees: Array
});

I assume you are using mongoose. Try
updated.markModified('attendees');
before
updated.save call.
Regarding pushing the currentUser, do something equivalent to
event.attendees.push({__v: 0
_id: "53dd72fb5a24aa781a3cbde8"
email: "test#test.com"
name: "Test User"
provider: "local"
role: "user"})
i.e just push the relevant fields.

Related

MongooseJS object undefined inside callback function

I'm trying to write an endpoint for an API that will return all orders for a given user. My issue is that when I try to query the database using mongoose's findById function, the 'user' object is undefined in the callback function and I can't query the orders subdoc. To add to the confusion, I can get it to work if I don't use a callback function, but then I don't have proper error handling.
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This works???
var u = user_model.findById(req.params.userid);
res.json(u.orders);
});
The following code throws the error "TypeError: Cannot read property 'orders' of undefined".
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This throws an error.
user_model.findById(req.params.userid).then(function (err, user) {
if (err) {
res.send(err);
}
res.json(user.orders);
});
});
user.js
var mongoose = require('mongoose');
var ordersSchema = require('./order').schema;
var userSchema = new mongoose.Schema({
name: String,
email: String,
showroom: String,
orders: [ordersSchema]
});
module.exports = mongoose.model('User', userSchema);
order.js
var mongoose = require('mongoose');
var lineItemsSchema = require('./lineitem').schema;
var ordersSchema = new mongoose.Schema({
trackingNumber: Number,
lineItems: [lineItemsSchema]
});
module.exports = mongoose.model('Order', ordersSchema);
Any help / explanation of this behavior would be appreciated. Thanks!
The first parameter of the then callback is user, not err.
Either use a traditional callback:
user_model.findById(req.params.userid, function (err, user) {
if (err) {
res.send(err);
return; // Need to return here to not continue with non-error case
}
res.json(user.orders);
});
Or chain a call to catch on the promise to separately handle errors:
user_model.findById(req.params.userid).then(function (user) {
res.json(user.orders);
}).catch(function(err) {
res.send(err);
});
I usually query like this, it work perfect :
user_model.find(_id : req.params.userid)
.exec((err, user) => {
if(err){
//handle error
}
return res.status(200).json(user.orders);
})
});

Using findOne and findOneAndUpdate with HTTP request (mongoose)

I am making an api rest in which I want to make HTTP requests using Postman, specifically I want to perform a search or update a mongodb document, but this must be by an id which is not the doc_id that provides mongo
models Schema
'use strict'
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const infoClientSchema = Schema ({
idusr: String, /*this is require*/
name: String,
phone: Number,
address: String,
riff: String,
state: String,
city: String,
email: {type: String}
})
module.exports = mongoose.model('InfoCli',infoClientSchema)
Controller (This is the get method I know using findById and is working)
'use strict'
const InfoCli = require('../models/infoclient')
function getInfoCli(req, res){
let infocliId = req.params.infocliId
InfoCli.findById(infocliId, (err, infocli) =>{
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!infocli) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infoclient: infocli})
})
}
Controller (This is the get method which I thought would work using findOne)
function getInfoByUsr(req, res){
let idusr = req.body.idusr
InfoCli.findOne(idusr, (err, infocli) => {
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!infocli) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infoclient: infocli})
console.log(infocli) /*The console is not showing anything*/
})
}
Controller (This is the put method which I thought would work using findOneAndUpdate)
function updateByUsr(req, res){
let idusr = req.body.idusr
let update = req.body
InfoCli.findOneAndUpdate(idusr, update, (err, infocliUpdate) => {
if (err) return res.status(500).send({message: 'Error making
request: $(err)'})
if (!idusr) return res.status(404).send({message: 'The client does
not exist '})
res.status(200).send({infocliente: infocliUpdate})
})
}
Routes (not 100% sure about this)
const express = require('express')
const InfoCliCtrl = require('../controllers/infoclient')
const api = express.Router()
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli) /*working*/
api.get('/infoclient/:idusr', InfoCliCtrl.getInfoByUsr)
In your app.js/server.js
you should have bodyparser installed
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli)
api.post('/infoclient/:idusr', InfoCliCtrl.updateByUsr)
If you are passing data as URL parameter, like this /infoclient/:infocliId then you can access that using req.params.infocliId
If you are passing using POST body then you can access data using req.body.
In infoClient.js
To fetch user data
exports.getInfoCli = function(req, res, next){
var incomingData = req.params.infocliId;
InfoCli.findOne({idusr: incomingData}, function(err, data){
if(err){
return res.status(500);
} else {
return res.status(200).send({infoclient: data})
}
});
}
Call the above code by
GET - http://localhost:port/infoclient/3874234634 this 3874234634 is your infocliId you need to pass in route
To update user data
exports.updateByUsr = function(req, res, next){
var userId = req.params.idusr;
var updateData = req.body;
InfoCli.findOneAndUpdate({idusr: userId}, updateData, {new: true }, function(err, data){
if(err){
return res.status(500);
} else {
return res.status(200).send(data)
}
});
}
In the update code we have used {new : true} is to return updated document from DB
Call the above code by
POST method - http://localhost:port/infoclient/3874234634 with data in POST body {name: 'pikachu', phone: 12345, ...}
so you read the userid in url parameter using req.params and body data in req.body
I think you simply need to change the line let idusr = req.body.idusr in your getInfoByUsr() function to let idusr = req.params.idusr
http://expressjs.com/en/api.html#req.body
http://expressjs.com/en/api.html#req.params
Also check the syntax of your findOne and findOneAndUpdate query (because idusr is not a Mongo _id but sort of custom String id):
InfoCli.findOne({ idusr: idusr }, (err, infocli) => { ...
InfoCli.findOneAndUpdate({ idusr: idusr }, update, (err, infocliUpdate) => {..
http://mongoosejs.com/docs/api.html#model_Model.findOne
Thank you all, your answers help me to correct many things in the code.
The problem was a horrible mistake in the routes
See how I was using the same path for two requests
api.get('/infoclient/:infocliId', InfoCliCtrl.getInfoCli) /*working*/
api.get('/infoclient/:idusr', InfoCliCtrl.getInfoByUsr)
The problem was that when I used the identifier for idusr it was in conflict with the ObjectId search
Now
api.get('/infoclient/idusr/:idusr', InfoCliCtrl.getInfoByUsr)

schema error mean app

I have a schema problem. I dont get the right schema in my api. here is my api :
var Meetup = require('./models/meetup');
module.exports.create = function (req, res) {
var meetup = new Meetup(req.body);
meetup.save(function (err, result) {
console.log(result);
res.json(result);
});
}
module.exports.list = function (req, res) {
Meetup.find({}, function (err, results) {
res.json(results);
});
}
The console.log displays { __v: 0, _id: 58343483ff23ad0c40895a00 } while it should display { __v: 0, name: 'Text input', _id: 58343076b80874142848f26e }
here is my model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Meetup = new Schema({
name: String,
});
module.exports = mongoose.model('Meetup', Meetup);
If req.body is undefined (as you wrote in the comments) then obviously new Meetup(req.body); cannot populate the new objects with any data (like {name: 'Text input'} or anything else) since it is called with undefined as an argument.
Make sure you use the body-parser and that you pass the correct data in your request.
Also, check for errors. Every callback that takes the err argument should be in the form of:
module.exports.list = function (req, res) {
Meetup.find({}, function (err, results) {
if (err) {
// handle error
} else {
// handle success
}
});
}
How to track the problem:
make sure you use the body-parser on the backend
make sure you pass the correct data on the frontend
make sure that the data passed by your frontend is in the correct place (body)
make sure that the data is in the correct format (JSON? URL-encoded?)
add console.log(req.body) after new Meetup(req.body); to know what you save
open the Network tab in the developer console of your browser and see what is transferred

How do I use Angular Controller to get data from Mongo database

I am trying to use controllers to modify a page according to the user.
I am using this:
$http.get('/someUrl').then(function(response){
$scope.firstname = response.data;
});
What I am trying to do is, get each of the fields from my database and use them accordingly.
If this is my schema and I already have a person stored in the database:
var personSchema = new mongoose.Schema({
firstname: {type: String, required: true, },
lastname: {type: String, required: true}
});
var person = mongoose.model('People', personSchema);
module.exports = person;
What URL will I use in '/someUrl' to get the firstname of the person that is currently signed in?
Also, am I missing any functionality that I need to execute this?
EDIT:
My route
router.post("/update-profile", function(req, res) {
if (!req.session.user) {
return res.status(401).send();
}
var firstname = req.body.firstname;
var lastname = req.body.lastname;
var newProfile = new UserProfile();
newProfile.firstname = firstname;
newProfile.lastname = lastname;
console.log(newProfile);
newProfile.save(function(err, savedProfile) {
if (err) {
console.log(err);
return res.status(500).send();
} else {
res.render("profile");
return res.status(200).send();
}
});
});
Get a person object from the url.
$http.get('/user?id=5').then(function(response){
$scope.user = response.data;
});
Where the id is the user id.
Then in your html you can use {{user.firstName}}.
You could also pass in req.user to the page when it loads, so you wouldn't need to do another get.
res.render('page',{user:req.user});
Then (in ejs)
$scope.user = <%=user%>;
What I feel is, you should have an end-point /api/users/:id that should expect an _id as request parameter.
So your get request would be like :
$http.get('/someUrl/' + current_logged_in_user_id).then(function(response){
$scope.firstname = response.data;
});
And your backend code would be something like:
app.get('/someUrl/:id', function(req, res){
User.findById(req.params.id, function (err, user) {
if(user) res.json(user.firstName);
});
});
Now from the information that you provided, that's the best I can tell you. You can use DaftMonk's Angular Fullstack Generator. It creates the whole Authentication Boilerplate for you. It automatically get user details based on session_id and adds the user to req.user. So in the request handler, you can simply get the requesting user's details by using req.user

How do I make sure that this variable gets defined?

I have this variable Blog which is a mongoose model. It gets defined here:
db.once("open", function(){
var userSchema = new mongoose.Schema({
username: String,
password: String
});
var blogSchema = new mongoose.Schema({
title: String,
content: String,
userId: String
});
User = mongoose.model("User", userSchema);
Blog = mongoose.model("Blog", blogSchema);
});
I want to use app.get to generate a url that looks like /post/blogpost_id/edit so I tried to do this:
Blog.find(function (err, posts){
app.get("/post/" + posts._id + "/edit/", checkAuth, function(req, res){
res.render("edit.html", {
pageTitle: "Edit",
pages: {
"Log Out": "/logout"
},
posts: posts
});
});
});
As you can imagine, that doesn't work. How can I fix this?
The reason is that Blog gets defined in an asynchronous callback, so your code gets further executed while node is waiting for the database to be opened and therefore will not be defined yet.
Also the defining of your route is extremely inefficient. You should define a route with a parameter: /post/:postID/edit and inside the callback check whether the post with the given ID exists. It will look like this afterwards (note that I don't know mongoose and wrote this after a quick check of the manual):
app.get("/post/:postID/edit/", checkAuth, function (req, res) {
Blog.find({ _id: req.params.postID }, function (err, posts) {
if (posts.length == 0) res.send(404, 'Not found');
else // yadayada
});
});

Categories

Resources