2012-04-23 17 views
11

Obecnie mam następujący zestaw danych:„upsert” w osadzonym dokumentu

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

Jeśli chcę zaktualizować wiersz z lokalizacji chciałbym uruchomić coś podobnego do:

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

to działa fine aż locale nie istnieje:

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

ponieważ istnieje indeks unikatowy na component_id ten wygeneruje excep narzekanie na duplikat klucza.

Czy istnieje sposób automatycznego dodania nowego "dokumentu" w innym miejscu i zaktualizowania go, jeśli już istnieje? Zgodnie z dokumentacją za pomocą operatora pozycji nie będzie działać z "upsertingiem".

Odpowiedz

10

Możesz użyć $addToSet, aby dodać do zestawu upewniając się, że nie ma duplikatu elementu tablicy, ale to nie zadziała w przypadku "aktualizacji".

Aby zrobić to, co chcesz, musisz zmienić strukturę danych do czegoś podobnego:

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

teraz można zrobić aktualizacji na lokalizacji nl_NL z tylko:

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

a nowa lokalizacja będzie działać jak dobrze, jak z:

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

może chcesz przy opracowaniu er do konieczności ustawienia regionalne w ramach zagnieżdżonego obiektu, a także być może, jak w:

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

To sprawia, że ​​łatwiej odzyskać dane w niektórych przypadkach.

+1

Cześć Derick, dziękuję za odpowiedź. Twoja sugestia była w rzeczywistości moją początkową strukturą danych, którą zmieniono na powyższą. Jednym z powodów było tworzenie indeksów na: _locales.url zamiast na wszystkich lokalizacjach: _locales.nl_NL.url, _locales.en_US.url itp. Obecnie rozwiązałem to poprzez uzyskanie wszystkich danych _locales i modyfikowanie/dodanie ustawień narodowych I "Pracuję z" ręcznie ". Kiedy skończyłem, zastępuję obecną "_locales" nową. Na razie to wystarczy, jeśli chodzi o wydajność, może to nie być dobry pomysł. –

+0

Zgadzam się, posiadanie "niezdefiniowanego" klucza nie jest często dobrym rozwiązaniem ze względu na indeksy. Czasami lepiej jest zrobić dwa zapytania, aby wykonać tę aktualizację, jeśli poprawia to wydajność z powodu indeksów/innych przyczyn w innych przypadkach. Przez większość czasu nie ma prawdziwej "właściwej drogi". Zagraj z nim, a jeśli nie działa, zmień go i uruchom dwa zapytania do aktualizacji. – Derick

+0

@Derick: Mam podobny problem. http://stackoverflow.com/questions/32038606/defining-a-map-with-objectid-key-and-array-of-strings-as-value-in-mongoose-schem –