How can I increment nested dynamic values?

Viewed 336

I have a database that's loosely created which has a key called website. Within this website object I will have multiple objects, one for each dynamically created website. An example of how the database could look would be

website: {
    google.com: {
        count: 19,
        like: {huge: 9, normal: 10},
        follow: {big: 11, small: 8}
    },
    facebook.com: {
        count: 1,
        like: {huge: 1},
        follow: {big: 1}
    }
}

So websites is initially an empty object and the more that happens, more random websites will be added (google, facebook being the example)

Now, I want the values inside incremented by 1 when I get a hit for those values, so for example

User.findByIdAndUpdate({"_id": id}, {
website: {
    [query.name]: { $inc : { //query.name is the dynamic name that'll be given
        count: 1, //I want this count value incremented by one
        like: {
            [query.like]: 1 //query.like would be either huge or normal or something that's not available yet, in which case it would be created with a value of 1. If it exists I want the value incremented by one.
        },
        follow: {
            [query.follow]: 1 //query.follow would be either big or small or something that's not available yet, in which case it would be created with a value of 1. If it exists I want the value incremented by one.
        }
    }}
}
}, function(err, result){
    if (err) {
        console.log(err);
    } else {
        console.log(result);
    }
});

But this isn't working, it gives me an error saying "Error: The dollar ($) prefixed field '$inc' in 'website.[dynamic website name].$inc' is not valid for storage."

I tried putting the $inc in a few other places but I got about the same message.

Any ideas? :(

1 Answers

You should use the dot notation when you want to refer to nested fields so your JS code should look like this:

let query = { name: "google.com", like: "huge", follow: "big" };

let update = {
   $inc: {
      [`website.${query.name}.count`]: 1,
      [`website.${query.name}.like.${query.like}`]: 1,               
      [`website.${query.name}.follow.${query.follow}`]: 1
   }
}

console.log(update);

You can try if that works. The problem is that you're using dots as subdocument names (google.com, facebook.com). The question is if MongoDB will be able to identify that key name is google.com as opposed to { google: { com: ... } }. I would suggest removing those dots from field names. You can use underscore instead of dot like google_com - that will be much more safe.

Related