'upsert' in an embedded document

2019-01-14 13:37发布

问题:

I currently have the following dataset:

{  
    'component_id':1,  
    '_locales':[   
        {  
            'url': 'dutch',  
            'locale': 'nl_NL'  
        } 
    ] (etc)
}

If I want to update the row with the locale I would run something similar to:

db.components.update(
    {'component_id': 1, '_locales.locale': 'nl_NL'},
    {$set: {'_locales.$': {'url': 'new url','locale':'nl_NL'}}, 
    true
);

This works fine untill the locale does not exists:

db.components.update(
    {'component_id': 1, '_locales.locale': 'en_US'},
    {$set: {'_locales.$': {'url': 'new url','locale':'en_US'}}, 
    true
);

since there is a unique index on component_id this will throw an exception complaining about a duplicate key.

Is there a way to automatically add the new 'document' with a different locale and update it if it already exists? According to the documentation using the position operator will not work with 'upserting'.

回答1:

You can use $addToSet to add to a set making sure there is no duplicate array element, but that will not work for your "updating" case.

In order to do what you want, you will need to change your data structure to something like:

{
    "_id" : ObjectId("4f9519d6684c8b1c9e72e367"),
    "component_id" : 1,
    "_locales" : {
        "nl_NL" : {
            "url" : "dutch"
        }
    }
}

Now you can do an update on the nl_NL locale with just:

db.components.update( { component_id: 1 }, { $set: { '_locales.nl_NL.url' : 'new url' } }, true );

And a new locale will work as well, such as with:

db.components.update( { component_id: 1 }, { $set: { '_locales.en_US.url' : 'American' } }, true );

You might want to consider to having the locale as part of the nested object as well perhaps, like in:

{
    "_id" : ObjectId("4f9519d6684c8b1c9e72e367"),
    "component_id" : 1,
    "_locales" : {
        "nl_NL" : {
            "url" : "dutch"
            "locale" : "nl_NL"                 
        }
    }
}

This makes it easier to retrieve data in some cases.



标签: mongodb