javascriptmongodbmeteorminimongo

MongoDB: Update nested array element or insert it if not existing


This is how a document structure could be in my case:

{
    "_id" : "P9H59RuSbnm45erj7",
    "description" : [
        {
            "content" : "Something",
            "language" : "en",
            "timestamp" : 1476958705
        },
        {
            "content" : "Irgendetwas",
            "language" : "de",
            "timestamp" : 1476958705
        }
    ]
}

Now I want to update the content of a specific language. But the description array could have missing languages.

{
    "_id" : "P9H59RuSbnm45erj7",
    "description" : [
        {
            "content" : "Something",
            "language" : "en",
            "timestamp" : 1476958705
        }
    ]
}

So what I am doing is to check first if the language is existing, then

  1. If it is existing, I will do a simple update / $set
  2. If it is not existing, I will do a update / $addToSet

My question is, if this can be simplified. Do I really have to check for the existing language and then use two different update-queries? With this the code gets pumped up...

I'm using this code in my meteor app, so I'm using minimongo.

if (Collection.find({ _id: 'P9H59RuSbnm45erj7', 'description.language': 'en' }).count() > 0) {
    Collection.update(
        {
            _id                   : 'P9H59RuSbnm45erj7',
            'description.language': 'en'
        },
        {
            $set: {
                'description.$.content'  : value,
                'description.$.timestamp': Math.floor(Date.now() / 1000)
            }
        }
    );
}
else {
    Collection.update(
        { _id: 'P9H59RuSbnm45erj7' },
        {
            $addToSet: {
                description: {
                    content  : value,
                    language : 'en',
                    timestamp: Math.floor(Date.now() / 1000)
                }
            }
        }
    );
}

Solution

  • db.Test8.update(
          { _id: 1, "description.language":{$eq:"en"} },
          {
                    $set: { "description.$.content": "content5" }
          },
          {}, function (err, result) {
    
              // if result.nMatched == 0 then make your $addToSet
              // because there are no query
    
           }
        );
    

    The benefit to have the query in this was is to make most of the time 1-query instead of 2. And only rarely time 2-query.

    Depending from your most frequently scenario. As you say most of the time is an update, then you can make 1query instead of 2 query.

    I don't know any other way to make it better.