Can someone please tell me why my POST method is not saving to my MongoDB via Mongoose?
My Angular controller
$scope.saveUpdate = function(id){
$http.post('/api/entry/' + id)
.success(function(data){
$scope.entry = data;
})
.error(function(data){
console.log('There was a problem saving your entry: ' + data);
});
// update page with remaining entries
$http.get('/api/entries').then(function(response){
$scope.entries = response.data;
});
}
My API
app.post('/api/entry/:entry_id', function(req, res){
if (req.params) {
Entries.findByIdAndUpdate({
_id : req.params,
// the properties we're updating and the new values
username: req.body.username,
date: req.body.date,
income: req.body.income
}, function(err, entry){
if (err) {
res.send(err) }
else {
res.send('Success!');
}
})
}
});
The submit button in the view
<button type="submit" class="btn" ng-click="saveUpdate(entry._id)">Update</button>
The updated entry hits the DOM when the button is clicked but when it hits the Angular core code it reverts back to its original state without updating the DB. No errors are thrown either.
There are a few things wrong in the code above:
The entire req.paramsobject is being passed to the _id field instead of req.params.entry_id
The way parameters are being passed to findByIdAndUpdate() is incorrect
The request body is never being sent over in your $http.post() but you're expecting the req.body to contain data in your route
req.params points to the whole params object on the request. You only want to get the ID from the params and then pass that into your mongoose model.
Assuming you're passing in the entry_id then you will pass your first condition if(req.params) since params will indeed exist. However, when you pass req.params to _id field of your Entries model you're actually passing in the whole object { entry_id: '123' } instead of just 123.
Additionally, the way you're passing in values to the findByIdAndUpdate method is incorrect. There are 4 params it will take findByIdAndUpdate(id, [update], [options], [callback]), id is the only required field. You're passing in the whole object to find based on id and update the values in a single argument. You need to break out entry_id from the fields you'd like to update.
app.post('/api/entry/:entry_id', function(req, res) {
// Param Existence Checking
if (!req.params.entry_id)
return res.status(400).send('an entry_id must be provided');
if (!req.body.username)
return res.status(400).send('a username must be provided');
if (!req.body.date)
return res.status(400).send('a date must be provided');
if (!req.body.income)
return res.status(400).send('an income must be provided');
var updateData = {
username: req.body.username,
date: req.body.date,
income: req.body.income
};
Entries.findByIdAndUpdate(req.params.entry_id, updateData, function(err, entry){
if (err)
return res.status(500).send(err)
return res.status(200).send('Success!');
})
});
Also based on sample code from your question, I don't see where you're passing in values to req.body when doing $http.put(). One thing for sure is that, if req.body doesn't contain username,date and income you would get undefined assigned to those fields.
To supply the request body via $http.post() pass it in to the second param data.
$http.post('/api/entry/' + id, {
username: 'username',
date: new Date(),
income: 10000.00
})
.then(function(res, status){
console.log(res.data);
})
.catch(function(err) {
console.log(err);
});
Additionally, don't use .success() in your promise chain, that approach is deprecated. You should use the A+ standard .then() and .catch() when handling your response.
Related
I want to show current user information from nodejs to angular(view).
The problem is that i don't know how to pass and how to get User Id in node and angular .
Code :
Node
router.get('/:id/api/data.json', function(req, res, next) {
console.log(req.params.id);
var userId = req.params.id;
User.findById({_id:userId}, function (err, doc) {
if (err) throw err
if (doc){
res.json({
doc: doc,
userID:req.params.id
});
}
});
});
Angular :
app.controller('profileCtrl', function($scope, $http) {
$http.get("don't know how to get id from node").then(function (response) {
console.log(response.data);
});
});
Your Node.js router is listening to the url /:id/api/data.json. The :id part of that means Node.js is expecting a paramater there, which will get picked up by req.params.id in your Node.js file.
This means that you actually have to be passing in an id value as a part of the url. So your url would look something like /userid12345/api/data.json.
In your Angular file, that's the url you're going to be making the get request to. Which means you need to know the user's ID in your Angular file so you can get that specific url, e.g.:
var userId = 'userid12345';
$http.get('/' + userId + '/api/data.json').then(function(response) {
console.log(response);
});
Once you pass userId in as a part of the url, then Node can grab it using req.params.id and you can make your db call.
I am trying to update an existing document in mongodb with node.js. But it does not seem to work. It do not even display the request call in the console. Please suggest what mistake I am doing or how I can I do the update operation in node.js with mongodb. Here is the code:
Node.js Code:
app.put('/addIssueId', function(req, res) {
console.log("Adding issue id")
console.log(req.body.issueKey)
impactMapFeature.update( {productName:req.params.productName, actor:req.body.actor, activity:req.body.activity,feature:req.body.feature},{issueKey:req.body.issueKey}, function ( err, data ) {
console.log("Updating" + data)
});
});
Angular Controller code:
var data = {
productName: $scope.productName,
actor: actor,
activity: impact,
feature : $('#feature').val(),
issueKey : data.key
};
$http.put('/addIssueId', data)
.success(function(data){
}).error(function(data){
console.log('Error in adding issueId' + data)
});
}
As chridam said, you are using req.params which is a route parameter. Either use the following route : /addIssueId/:productName or pass your variable with a query parameter : /addIssueId?productName=productName and {productName = req.query.productName, ... }, or pass your variable as you are doing it in the body (then you just need to change req.params.productName to req.body.productName
When I save new data to a DataStore in Angular, I don't want to specify the _id. The system automatically assigns one. From looking at the network trace, the _id is passed back to the application in the response - https://baas.kinvey.com/appdata/appxxx/activities/54ac3d8671e2d7933b0116b4 - but I don't see anyway of finding that in the Angular documentation about how to retrieve that _id so I can add it to an existing list or do other processing.
var promise = $kinvey.DataStore.save('activities', {
text : $scope.newActivity.text ,
duedate : '2015-01-01'
});
promise.then(
function () {
$scope.newActivity.text = '';
},
function (error) {
//Kinvey insert finished with error
alert("Error insert: " + JSON.stringify(error));
});
Kinvey will actually return the object to you in the promise, and you can just grab the _id off the returned object.
promise.then(function(data) {
// Here's where you get your _id
$scope.newActivity.text = data._id;
}, function(err) {
console.error(err);
});
I use $resource to get data from Facebook's Graph api:
resource = $resource(
"https://graph.facebook.com/v2.2/:api/:id/:node/"
)
So for instance, I made a successful request to 'https://graph.facebook.com/v2.2/user.id/albums/' by:
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
and the response shows (in Chrome dev tool console):
Resource
- $promise: Promise
- $resolved: true
- data: Array[9]
- 0: Object
- 1: Object2:
- length: 9
- __proto__: Array[0]
- paging: Object
- __proto__: Resource
So I naively try to add under console.log response another console.log response.data,
but it shows 'undefined'.
So I wonder how to extract the data object?
========================== EDIT ========================
It seems the reason being
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
is chained after another resource request as follows:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
}).then(function(response) {
console.log("response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
In this case Log #1 will log out the resource object with data being an array, while Log #2 gives undefined.
If I do not chain the then function, but put the last one inside the previous .then, I have the expected results:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
}).$promise.then(function(response) {
console.log("A: response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
});
gives Log #1 the same result, while Log #2 is an array of 9 elements.
** So I wonder I is the problem of the original method?**
What's happening in your first attempt is that in your second then() you are returning the return value of FB.resource.get(), but this value is not a promise, so this then() resolves immediately, and processing moves on to the next then() before the data is done being retrieved. When you view the values in your Chrome debugger, you are stopping the execution long enough for the request to finish, and the data is populated when you observe it. (There is a term for this phenomenon, by the way.)
According to the notes on this pull request and this note in the developer's guide, you should be using instance.$promise if you want to chain off of a resource request. So your second approach that uses $promise is more or less the correct way to go about it.
Your code can be cleaned up a bit. Unless you have a reason to want a separate step to extract the FB user id and pass it to the next step, you can remove the first .then(). There is some other tidying up that you can do as well:
FB.get_user()
.then(function (response) {
var user_id = response.id;
// the value assigned to self.albums here is a (mostly) empty object that will
// be populated with data when the request finishes
self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
return self.albums.$promise;
})
.then(function (response) {
// (avoid putting a [then] inside another [then] unless you need to)
console.log("A: response", response);
console.log("response.data", response.data);
return response.data;
});
I'm trying to find just the store that matches my id parameter. In terminal everything looks fine:
GET /admin/company?_id=5470e913d20b3dab7c13218b 200 219.590 ms - -
And then here's my $resource
angular.module('mean.management').factory('Companies', ['$resource',
function($resource) {
return $resource('/admin/company/:companyId', {
companyId: '#_id'
}, {
update: {
method: 'PUT'
},
get: {method: 'GET',isArray: true}
});
}
]);
It's searching with the right _id but it returns a list of a bunch of companies instead of just the one company.
Here's the controller
$scope.newStore = function () {
Companies.get({
_id: $scope.global.user.company // _id works fine
}, function (company2) {
console.log(company2); // this logs 40 different companies when it should be one matching the _id
});
};
If I replace Companies.get with Companies.query, it's the same problem. Doesn't change anything. I also changed get: {method: 'GET', isArray: false} instead of true, and that just returns an error in the browser console (because it's an array).
Update: I know the parameter is correct because if I go to localhost:3000/admin/company?_id=5470e913d20b3dab7c13218b and ctrl+f 5470e913d20b3dab7c13218b I can see the object with that _id in it.
Update2: I think I'm getting closer to a solution. If I comment out this, it doesn't return any articles
// routes
app.get('/admin/company', companies.all); // if I comment this, it won't return anything
app.get('/admin/company/:companyId', companies.oneCompany); // this doesn't seem to be doing anything
Update3
Here are some examples of server-side code
exports.oneCompany = function(req, res, next, id) {
Company.load(id, function(err, article) {
if (err) return next(err);
if (!article) return next(new Error('Failed to load article ' + id));
req.article = article;
res.json(req.article);
next();
});
};
Here's another one I tried
exports.company1 = function (req, res, next, id) {
Company
.findOne({
_id: id
})
.exec(function (err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
res.json(user);
next();
});
};
I am fairly new to ngresource myself and figured similar things out last week my self. Your issue here is the resource definition where you generate the companyId into URL path but not as parameter when you define the resouce like this:
return $resource('/admin/company/:companyId', {
companyId: '#_id'
},
What you would need is just simply this:
return $resource('/admin/company')
And use this $resource as
app.get({_id:companies.oneCompany});
This generates resource URLs as /admin/company?_id=XYZ. This part is documented in https://docs.angularjs.org/api/ngResource/service/$resource as paramDefaults:
Each key value in the parameter object is first bound to url template
if present and then any excess keys are appended to the url search
query after the ?.
Given a template /path/:verb and parameter {verb:'greet',
salutation:'Hello'} results in URL /path/greet?salutation=Hello.
Hope this helps.