2013-05-06 7 views
9

Korzystanie Mongoose wersję 3.6.4Mongoose.js: Atomowa aktualizacja właściwości zagnieżdżonych?

że mam dokument MongoDB tak:

{ 
    "_id" : "5187b74e66ee9af96c39d3d6", 
    "profile" : { 
     "name" : { 
      "first" : "Joe", 
      "last" : "Pesci", 
      "middle" : "Frank" 
     } 
    } 
} 

I mam następujący schemat dla użytkowników:

var UserSchema = new mongoose.Schema({ 
    _id: { type: String }, 
    email: { type: String, required: true, index: { unique: true }}, 
    active: { type: Boolean, required: true, 'default': false }, 
    profile: { 
    name: { 
     first: { type: String, required: true }, 
     last:  { type: String, required: true }, 
     middle: { type: String } 
    } 
    } 
    created: { type: Date, required: true, 'default': Date.now}, 
    updated: { type: Date, required: true, 'default': Date.now} 
); 

I złożyć formularz mijania pole o nazwie: profile[name][first] o wartości: Joseph

i dlatego chcę zaktualizować tylko plik użytkownika RST nazwa, ale pozostawić jego ostatni i środkowy sam, myślałem, że po prostu zrobić:

User.update({email: "[email protected]"}, req.body, function(err, result){}); 

Ale kiedy to zrobić, to „usunięcie” tych profile.name.last i profile.name.middle właściwości i skończyć z dokumentu, który wygląda jak :

{ 
    "_id" : "5187b74e66ee9af96c39d3d6", 
    "profile" : { 
     "name" : { 
      "first" : "Joseph" 
     } 
    } 
} 

Więc to w zasadzie nadpisywania wszystkich profile z req.body.profile, co chyba ma sens. Czy jest jakiś sposób obejścia tego bez konieczności wyraźniejszego określania pól w kwerendzie aktualizacji zamiast req.body?

+0

Rozważ zaakceptowanie odpowiedzi Aichholzera, ponieważ zapewnia ona prawdziwe rozwiązanie problemu. – zbr

Odpowiedz

7

Jesteś poprawne, Mongoose konwertuje aktualizacje $set dla Ciebie. Ale to nie rozwiązuje twojego problemu. Wypróbuj go w powłoce mongodb, a zobaczysz to samo zachowanie.

Zamiast tego, aby zaktualizować pojedynczą głęboko zagnieżdżoną właściwość, należy podać pełną ścieżkę do właściwości głębokości w $set.

User.update({ email: '[email protected]' }, { 'profile.name.first': 'Joseph' }, callback) 
+3

Dobrze, ale miałem nadzieję, że mogę po prostu przekazać w 'req.body', więc nie musiałem określać wszystkich możliwych pól. Tak więc skończyłem robiąc 'findById()' najpierw, usuwając '__v' i' _id' z odnalezionego dokumentu, używając '_.deepExtend()', aby scalić nowe zaktualizowane właściwości, a następnie przekazując mój obiekt frankenstein do Mongoose 'update'. – k00k

+1

@Aaronheckmann, czy jest tak czy inaczej mongoose lub mongo, że "tutaj jest mój ostatni obiekt, po prostu zaktualizuj go"? –

+0

@ k00k - Czy to podejście atomowe? Czy jeszcze nie napisze całego dokumentu? Dlaczego musisz usunąć __v i _id? –

0

myślę szukasz $ set

http://docs.mongodb.org/manual/reference/operator/set/

User.update({email: "[email protected]"}, { $set : req.body}, function(err, result){}); 

Spróbuj że

+0

Myślałem, że Mongoose jest domyślnie "bezpieczny", więc "aktualizacja" naprawdę jest "$ set", czy jestem w błędzie? – k00k

+0

I dodać, po prostu wypróbowałem i to nie działa. Wygląda na problem z zagnieżdżonymi właściwościami. Dla wyjaśnienia, tylko zagnieżdżone właściwości na tym samym poziomie (rodzeństwo) zostają zniszczone. – k00k

+0

szukasz zestawu $ z konkretną nazwą pola - "name.first". Nie ma to nic wspólnego z bezpiecznymi i niebezpiecznymi zapisami, tylko z informacją, czy chcesz zaktualizować cały dokument lub pojedyncze pole. –

0

Może to dobre rozwiązanie - dodać możliwość Model.update, że zastąpienie zagnieżdżonych obiektów, takich jak:

{pole1: 1, fields2: {A: 1, B: 2}} => { 'pole1': 1 'field2.a': 1 'field2.b' 2}

nestedToDotNotation: function(obj, keyPrefix) { 
    var result; 
    if (keyPrefix == null) { 
     keyPrefix = ''; 
    } 
    result = {}; 
    _.each(obj, function(value, key) { 
     var nestedObj, result_key; 
     result_key = keyPrefix + key; 
     if (!_.isArray(value) && _.isObject(value)) { 
     result_key += '.'; 
     nestedObj = module.exports.nestedToDotNotation(value, result_key); 
     return _.extend(result, nestedObj); 
     } else { 
     return result[result_key] = value; 
     } 
    }); 
    return result; 
    } 

});

potrzebują ulepszeń okrągły obsługę odniesienia, ale jest to bardzo przydatne podczas pracy z obiektów zagnieżdżonych

używam podkreślenia.js tutaj, ale te funkcje łatwo można zastąpić innymi analogami

8

jeden bardzo prosty sposób rozwiązać ten z Moongose 4.1 i pakiet flat:

var flat = require('flat'), 
    Schema = mongoose.Schema, 
     schema = new Schema(
      { 
       name: { 
        first: { 
         type: String, 
         trim: true 
        }, 
        last: { 
         type: String, 
         trim: true 
        } 
       } 
      } 
     ); 

    schema.pre('findOneAndUpdate', function() { 
     this._update = flat(this._update); 
    }); 


    mongoose.model('User', schema); 

req.body (na przykład) można teraz:

{ 
    name: { 
     first: 'updatedFirstName' 
    } 
} 

Obiekt zostanie spłaszczony przed wykonaniem faktycznego zapytania, dlatego $set zaktualizuje tylko oczekiwane właściwości zamiast całego obiektu name.

+0

po prostu należy zachować ostrożność podczas zagnieżdżania ObjectId. flat zamieni je w "something._bsontype": "ObjectID", "something.id": " – tdecs

Powiązane problemy