There are a couple of things in here that are not great, but first to cover the basics and get you going.
The first thing is to fix the method calling the service angular side. The API endpoint certainly does not expect the MongoDB update syntax you are using, but rather just an object. So first fixing that:
$scope.saveComment = function(i){
console.log("id is " + i);
// Split these out so they are easy to log and debug
var path = '/api/its' + i;
// This must mirror the structure expected in your document for the element
// Therefore "comments" is represented as an array of objects, even
// where this is only one.
var data = {
comments: [{
words: $scope.comment,
userId: $scope.getCurrentUser().name
}]
};
// Call service with response
$http.put(path,data).success(function(stuff){
document.location.reload(true);
});
}
Now your server API end has some faults, I would prefer a total redesign, but in lack of info, just concentrating on fixing the main problems without changing much.
Assuming this is the lodash library, the .merge()
function here is implemented incorrectly. It needs to be told how to "handle" the array content in the "merge" properly, and at present the best that will happen is an "overwrite". So we give it some smarts:
// Updates an existing it in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
It.findById(req.params.id, function (err, it) {
if (err) { return handleError(res, err); }
if(!it) { return res.send(404); }
var updated = _.merge(it, req.body,function(a,b) {
if (_.isArray(a)) {
return a.concat(b); // join source and input
}
});
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, updated);
});
});
};`
But there is a catch to that, as it will only "append" to the array. So if you put something in your input that was already there, then both the original items and anything in the array input would be added.
Dealing with that is a whole other issue to work out, depending on your needs.
From my own perpective, I would just send the array where possible and have an endpoint that is "just" for appending to the array of the document, rather than a "generic" document update as you have here.
This allows you to better utilize the MongoDB update functions, per expected actions. So something like this in the service call:
// comment can just be a singular object now
$http.put(path,{
"words": "this that",
"userId": 123
}).success(function(stuff){
And on the server API end:
exports.addComment = function(req, res) {
if(req.body._id) { delete req.body._id; }
It.findByIdAndUpdate(req.params.id,
{ "$push": { "comments": req.body } },
{ "new": true },
function(err,it) {
if (err) { return handleError(res, err); }
if(!it) { return res.send(404); }
return res.json(200, it);
}
);
};
So that will simply take the body of a "comment" and append it to the array. Most importantly it does this "atomically", so that no other possible request could collide in doing something like the current "merge" is doing. Other requests to the same endpoint will just "append" to the array in the current state as when the request is made, and so will this.
That is what the $push
operator is for, so it's wise to use it.
Some food for thought.
i
in the function's argument is the MongoDB_id
for a particular post. So, the endpoint is therefore just an associated JavaScript object with a bunch of key/value pairs -- one of which beingcomments
– Peter Ward 2 days ago/api/its
. What is the server code for that method? Is it your own application or a provider API? If the latter, then who is the provider? – Blakes Seven 2 days agohttp://localhost:9000/api/its/:id
, where:id
is thei
is said function's argument. – Peter Ward 2 days ago