2012-04-23 9 views
11

J'ai actuellement l'ensemble de données suivantes:« upsert » dans un document incorporé

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

Si je veux mettre à jour la ligne avec les paramètres régionaux que je courrais quelque chose de similaire à:

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

Cela fonctionne bien jusqu'à ce que le lieu n'existe pas:

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

car il y a un index unique sur ce ID_composant lancera une excep tion se plaignant d'une clé en double.

Existe-t-il un moyen d'ajouter automatiquement le nouveau 'document' avec une locale différente et de le mettre à jour s'il existe déjà? Selon la documentation utilisant l'opérateur de position ne fonctionnera pas avec 'upserting'.

Répondre

10

Vous pouvez utiliser $addToSet pour ajouter à un ensemble en vous assurant qu'il n'y a aucun élément de tableau en double, mais cela ne fonctionnera pas pour votre cas de "mise à jour".

Pour faire ce que vous voulez, vous devrez changer votre structure de données à quelque chose comme:

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

Maintenant, vous pouvez faire une mise à jour sur les paramètres régionaux nl_NL avec juste:

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

Et une nouvelle locale fonctionnera aussi bien, comme avec:

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

Vous pouvez consi er à avoir les paramètres régionaux dans le cadre de l'objet imbriqué et peut-être, comme dans:

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

Cela rend plus facile de récupérer des données dans certains cas.

+1

Bonjour Derick, merci d'avoir répondu. Votre suggestion était en fait ma structure de données initiale que j'ai changé à ce qui précède. Une raison était la création des index sur: _locales.url plutôt que sur tous les paramètres régionaux: _locales.nl_NL.url, _locales.en_US.url etc Actuellement, j'ai résolu cela en obtenant toutes les données _locales et modifier/ajouter les paramètres régionaux I Je travaille avec 'manuellement'. Quand j'ai fini, je remplace le '_locales' actuel par le nouveau. Pour l'instant cela suffira, la performance sage ce n'est peut-être pas une très bonne idée. –

+0

Je suis d'accord, avoir une clé "non-définie" n'est pas souvent une bonne chose à faire à cause des index. Parfois, il est préférable de faire deux requêtes pour faire cette mise à jour si cela améliore les performances en raison d'index/autres raisons dans d'autres cas. Il n'y a pas vraiment de "bonne façon" la plupart du temps. Jouez avec, et si cela ne fonctionne pas, changez-le et lancez deux requêtes de mise à jour. – Derick

+0

@Derick: Je suis confronté à un problème similaire. http://stackoverflow.com/questions/32038606/defining-a-map-with-objectid-key-and-array-of-strings-as-value-in-mongoose-schem –

Questions connexes