Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free.

I'm trying to append a bunch of comments to a MongoDB array with AngularJS's $http service, but I seem to have hit a dead end. Here is the code I tried (which crashed my DOM):

$scope.saveComment = function(i){
      console.log("id is " + i);
      $http.put('/api/its/' + i, { comments: {$push: { words: $scope.comment, userId: $scope.getCurrentUser().name } } } ).success(function(stuff){
         document.location.reload(true);
       })
    }

I was trying to use MongoDB's $push method to do this, but Angular won't have it. Any clue as to how I could do this?

Sincerely,

Peter

P.S.

Here is the server-side code for that particular model's update functionality :

// 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);
    updated.save(function (err) {
      if (err) { return handleError(res, err); }
      return res.json(200, it);
    });
  });
};`
share|improve this question
    
What is your API endpoint? It appears to be your own server application, so what it is supposed to receive on that endpoint for a PUT request? –  Blakes Seven 2 days ago
    
The 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 being comments –  Peter Ward 2 days ago
    
An "EndPoint" is the URL in your request i.e /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 ago
    
Yes, this is my own application. The actual url would be something like this: http://localhost:9000/api/its/:id, where :id is the i is said function's argument. –  Peter Ward 2 days ago
1  
Ok, let me grab some code real quick. –  Peter Ward 2 days ago

1 Answer 1

up vote 1 down vote accepted

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.

share|improve this answer
    
Dude...don't want to sound cheesy but how did you get to be so awesome? This code is sick, dude! (for the non-believers out there, it works exactly like I envisioned~) Though I'm on a schedule right now (have a "meet and greet" coming up to show my bootcamp work so that, maybe, I can find a job! #unemployed), when I get the chance I will take a closer look at the lodash library and try to master your second offering here. Thanks, Blakes Seven! –  Peter Ward 2 days ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.