2012-04-23 20 views
11

Al momento ho il seguente set di dati:'upsert' in un documento incorporato

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

Se voglio aggiornare la riga con il locale vorrei correre qualcosa di simile a:

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

questo funziona bene fino a quando il locale non esiste:

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

poiché non v'è un indice univoco component_id questo genera un ecce lamentandosi di una chiave duplicata.

C'è un modo per aggiungere automaticamente il nuovo 'documento' con una diversa localizzazione e aggiornarlo se esiste già? Secondo la documentazione utilizzando l'operatore di posizione non funzionerà con 'upserting'.

risposta

10

È possibile utilizzare $addToSet da aggiungere a un set assicurandosi che non vi sia alcun elemento di matrice duplicato, ma che non funzionerà per il caso di "aggiornamento".

Per fare ciò che si vuole, è necessario modificare la struttura dei dati a qualcosa di simile:

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

Ora si può fare un aggiornamento sulla localizzazione nl_nl con appena:

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

E un nuovo locale funziona altrettanto bene, come ad esempio con:

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

si potrebbe desiderare di conside er ad avere il locale come parte dell'oggetto nidificato pure, forse, come in:

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

Questo rende più facile per recuperare i dati in alcuni casi.

+1

Ciao Derick, grazie per la risposta. Il tuo suggerimento era in realtà il mio datastructure iniziale che ho modificato in precedenza. Uno dei motivi era la creazione degli indici su: _locales.url piuttosto che su ogni locale: _locales.nl_NL.url, _locales.en_US.url ecc. Attualmente ho risolto questo ottenendo tutti i dati di _locales e modificando/aggiungendo il locale I sto lavorando con 'manualmente'. Quando ho finito, sostituisco l'attuale "_locales" con quello nuovo. Per ora questo è sufficiente, per quanto riguarda le prestazioni questa potrebbe non essere una buona idea. –

+0

Sono d'accordo, avere una chiave "non definita" spesso non è una buona cosa a causa degli indici. A volte, è meglio fare due query per fare quell'aggiornamento se questo migliora le prestazioni a causa di indici/altri motivi negli altri casi. Non esiste un vero "modo corretto" il più delle volte. Gioca con esso, e se non lo fa cambia indietro ed esegui due query per l'aggiornamento. – Derick

+0

@Derick: sto affrontando un problema simile. http://stackoverflow.com/questions/32038606/defining-a-map-with-objectid-key-and-array-of-strings-as-value-in-mongoose-schem –

Problemi correlati