8

I have a node object that looks like this:

{
   "_id":"58b336e105ac8eec70aef159",
   "name":"my node",
   "ip":"192.168.1.1",
   "__v":0,
   "configuration":{
       "links":[
         {
            "linkName":"athena_fw_listen_tcp_5555",
            "_id":"58b336e105ac8eec70aef15d",
            "local":true
         },
         {
            "linkName":"athena_fw_listen_udp_5554",
            "_id":"58b336e105ac8eec70aef15c",
            "local":true
         }
      ]
   }
}

I am sending a delete request to my express server that looks like this: DELETE http://localhost:9000/api/nodes/58b336e105ac8eec70aef159/links/58b336e105ac8eec70aef15d

I followed instructions in $pull mongodb documentation and I also tried this

But it does not seem to work, as I keep receiving: 500 (Internal Server Error)

This is how the code on my express side looks like:

exports.destroyLink = function(req, res) {
    Node.findById(req.params.id, function(err, node) {
        if (err) { return handleError(res, err); }
        if (!node) { return res.status(404).send('Not Found'); }
        console.log("Node", JSON.stringify(node))
        console.log("Params", req.params)

        node
            .update({ '_id': req.params.id }, { $pull: { 'configuration': { 'links': { '_id': req.params.linkId } } } }, false, true)
            .then(err => {
                if (err) { return handleError(res, err); }
                return res.status(204).send('No Content');
            });
    })
};

The express router contains this: router.delete('/:id/links/:linkId', controller.destroyLink);

So I am expecting id and linkId as params, I use id (_id: req.params.id) to target a specific node and linkId (_id: req.params.linkId) to target a specific link, but it doesn't work!

Need help resolving the issue, I don't know what I am missing here!

Community
  • 1
  • 1
elmiomar
  • 1,747
  • 2
  • 17
  • 27
  • Can you try `{ $pull: { 'configuration.links': { '_id': req.params.linkId } } }` ? – s7vr Feb 26 '17 at 20:52
  • @Veeram I tried what you suggested before and I tried it now, but it does not work! :'( I updated my line of code to this: `node.update({ '_id': req.params.id }, { $pull: { 'configuration.links': { '_id': req.params.linkId } } }, function(err, data) { console.log("Data", data) if (err) { return handleError(res, err); } return res.status(204).send('No Content'); });` this what I get in the console: `Data { ok: 1, nModified: 0, n: 1 }` – elmiomar Feb 26 '17 at 21:06
  • okay not sure how to fix it as is. On a side note, `configuration` key is redundant in your document. You can remove it if it works for you and then you can access `links` as mentioned in docs. – s7vr Feb 26 '17 at 21:14
  • Oh, that's because I am planning on adding other elements to `configuration`, so I would prefer keeping it this way. Thank you anyways, I appreciate it! – elmiomar Feb 26 '17 at 21:18
  • You are welcome. So I looked into further. I don't much about mongoose. You can verify the `_id` is defined as `String` in your mongoose schema. If it is defined as `ObjectId` then you have to convert `req.params.id` and `req.params.linkId` into `ObjectId` before passing it to query. Btw the query edit I suggested above works fine from mongo shell. – s7vr Feb 26 '17 at 21:41
  • I tried converting the parameter to `mongoose.Types.ObjectId`. As far as I understand from this line below, the delete request was accepted and successful. `DELETE /api/nodes/58b356a18f54358c5b9c2123/links/58b356a18f54358c5b9c2127 204 13ms` However, the node object appears to still have the link_to_delete in its 'configuration.links' array. – elmiomar Feb 26 '17 at 22:41

5 Answers5

17

Hi all and thank you for your help. I finally got it to work!!!

After almost 3 hours of troubleshooting :'( :'( this is the solution that used:

exports.destroyLink = function(req, res) {
Node.findByIdAndUpdate(
    req.params.id, { $pull: { "configuration.links": { _id: req.params.linkId } } }, { safe: true, upsert: true },
    function(err, node) {
        if (err) { return handleError(res, err); }
        return res.status(200).json(node.configuration.links);
    });
};

Instead of findById then update the node, I did both using findByIdAndUpdate. It' working perfectly now!!!

I still don't find an explanation for the other version though. But anyways glad it's working this way.

elmiomar
  • 1,747
  • 2
  • 17
  • 27
  • Thanks, after spending lots of time your answer resolved my issue . To make findByIdAndUpdate work I had to set useFindAndModify to false ( mongoose.connect(uri, { useFindAndModify: false }); ) – Vishwanath Apr 10 '20 at 14:56
3

I had a similar issue getting a query like yours working. I think your query is not finding the id you're looking for. If you want to find an object in mongo by '_id' it needs to be passed in as an ObjectId. Try modifying things so it looks like this:

const mongo = require('mongodb');
var oId = new mongo.ObjectID(req.params.id);
update({ '_id': oId }, { $pull: { 'configuration': { 'links': { '_id': req.params.linkId } } } }, false, true)
William Chou
  • 752
  • 5
  • 16
  • I tried converting the parameter to both `mongoose.Types.ObjectId` and as you suggested above `mongo.ObjectID`. As far as I understande from this line below, the delete request was accepted and successful. `DELETE /api/nodes/58b356a18f54358c5b9c2123/links/58b356a18f54358c5b9c2127 204 13ms` However, the node object appears to still have the link_to_delete in its 'configuration.links' array. – elmiomar Feb 26 '17 at 22:34
1

I never got this working using the mongodb $pull operator. An alternative is to find the document then update the array using the mongoose pull method. The pull method can take an id string as its single argument and knows how to handle it. For this example using promises the code would look something like:

exports.destroyLink = function(req, res) {
  Node.findById(req.params.id)
    .then(node => {
      node.configuration.links.pull(req.params.linkId)
      return node.save()
    .then(node => res.send(node.configuration.links))
}

The mongoose docs for pull

kendlete
  • 214
  • 4
  • 13
0

I got the .update mongoose function to work by changing to this:

{ $pull: { 'configuration': { 'links': { '_id': ''+req.params.linkId+'' } } } }

Once you concatenate that, it'll pull it from the array.

0

For my problem, this worked

await FormSchema.updateOne({formName: name}, {$pull: {fields: {fieldName: fieldName}}}).exec();

and here is what my schema looks like

{
"fields": [
    {
        "contentType": "Text",
        "fieldName": "First Name",
        "textType": "short",
        "isUnique": false
    },
    {
        "contentType": "Boolean",
        "fieldName": "Contact Me"
    }
],
"_id": "61f71efd14cafb5a50ba365f",
"formName": "Contact",
"__v": 4

}