Search code examples
arraysmongodbmongodb-update

MongoDB Bulk.find.update() not modifying array objects, only adding new ones


I have a problem with MongoDB $set & $-operators. I try to modify an existing array

My update method looks about like this (I cannot get the exact copy as it is written in Clojure/Monger):

    bulk.find({
            _id: 2,
            channelStatuses.channel: {$eq: "BAR"}
    }).update({
            $set: {"channelStatuses.$.status": "error" }
    });

My data looks something like this:

{
  "_id" : "1",
  "channelStatuses" : [
    {
      "channel" : "FOO",
      "status" : "done"
    }
  ]
},
{
  "_id" : "2",
  "channelStatuses" : [
    {
      "channel" : "BAR",
      "status" : "done"
    }
  ]
},
{
  "_id" : "3",
  "channelStatuses" : [
    {
      "channel" : "BAZ",
      "status" : "error"
    }
  ]
},
{
  "_id" : "3",
  "channelStatuses" : []
}

So what I want it to do is to modify the status of the channelStatuses-object of document with _id = 2.

Instead it creates a new object inside the channelStatuses array, and the document looks like this:

    {
      "_id" : "2",
      "channelStatuses" : [
        {
          "channel" : "BAR",
          "status" : "done"
        },
        {
          "channel" : "BAR",
          "status" : ""
        }
      ]
    },

Solution

  • So I found couple of issues with your query.

    1. In your document, _id field is a text value, but in query you are using it as numeric.

    2. In your query channelStatuses.channel: {$eq: "BAR"} is invalid. JSON key can't have . inside unless you escape with double quotes.

    3. You can simplify channelStatuses.channel: {$eq: "BAR"} to "channelStatuses.channel": "BAR"

    Now try following query and see if it works.

    var bulk = db.doc.initializeUnorderedBulkOp();
    
    bulk.find({ 
      _id: "2", 
      "channelStatuses.channel": "BAR" 
      }).update({
                $set: {"channelStatuses.$.status": "error" }
      });
    
    bulk.execute();
    

    It should just update existing field. See final output below

    { 
        "_id" : "1", 
        "channelStatuses" : [
            {
                "channel" : "FOO", 
                "status" : "done"
            }
        ]
    }
    { 
        "_id" : "2", 
        "channelStatuses" : [
            {
                "channel" : "BAR", 
                "status" : "error"
            }
        ]
    }
    { 
        "_id" : "3", 
        "channelStatuses" : [
            {
                "channel" : "BAZ", 
                "status" : "error"
            }
        ]
    }