2013-04-08 13 views
15

Mongoose ile bir seferde bir (alt) belgede birden çok özellik ayarlamak mümkün mü? Ben çalışıyorum bir örnek yapmak:nodejs/mongoose ile bir alt belgenin kısmi güncelleştirmesi

var subSchema = new Schema({ 
    someField: String, 
    someOtherField: String 
}); 

var parentSchema = new Schema({ 
    fieldOne: String, 
    subDocs: [subSchema] 
}) 

Sonra yapmak istiyorsunuz:

exports.updateMyDocument = function(req, res) { 
    var parentDoc = req.parentDoc; // The parent document. Set by parameter resolver. 
    var document = req.myDoc; // Sub document of parent. Set by parameter resolver. 
    var partialUpdate = req.body; // updated fields sent as json and parsed by body parser 
    // I know that the statement below doesn't work, it's just an example of what I would like to do. 
    // Updating only the fields supplied in "partialUpdate" on the document 
    document.update(partialUpdate); 
    parentDoc.save(function(err) { 
     if(err) { 
      res.send(500); 
      return; 
     } 
     res.send(204); 
    }); 
}; 

Normalde kullanarak bu elde edebiliriz

en Bu şemayı var diyelim $set işleci, ancak benim sorunum bu örnekte documentparentDoc bir alt belgenin (gömülü şeması) olmasıdır. Bu yüzden subDocs._id tarafından tanımlanan alt belge örneği yerini

Parent.update({_id: parentDoc._id, "subDocs._id": document._id}, 
    {$set: {"subDocs.$" : partialUpdate}}, 
    function(err, numAffected) {}); 

yapmaya çalıştığımızda. Şu anda sadece alanları elle ayarlayarak "çözdüm", ancak bunu yapmanın daha iyi bir yolunu umuyordum.

cevap

29

programlı nokta gösterimi kullanılarak sadece bu alanları güncellemek için partialUpdate alanlarında dayalı bir $set nesnesi oluşturun:

var set = {}; 
for (var field in partialUpdate) { 
    set['subDocs.$.' + field] = partialUpdate[field]; 
} 
Parent.update({_id: parentDoc._id, "subDocs._id": document._id}, 
    {$set: set}, 
    function(err, numAffected) {}); 
+0

Evet, ilk bunu yaptı. Ama bunu yapmak zorunda olmadığımı umuyordum. – NilsH

+0

Bunu kabul etmek, bunu yapmanın tek yolu gibi görünüyor. Bu durumda, "hasOwnProperty" denetimi için herhangi bir ihtiyaç var mı, yoksa istek gövdesinden bir JSON nesnesi olduğundan bu gerekli değil mi? – NilsH

+0

Özellikleri döngülemek için biraz daha iyi bir yol, "Object.keys" işlevini kullanmak olabilir, çünkü yalnızca "kendi özellikleri" ni içerecektir (muhtemelen başka özellikler olmayacaktır). – NilsH

6

ben REST uygulamada, farklı yaptık.

router.put('/:id/:resource/:resourceId', function(req, res, next) { 
    // this method is only for Array of resources. 
    updateSet(req.params.id, req.params.resource, req, res, next); 
}); 

ve

function updateSet(id, resource, req, res, next) { 
    var data = req.body; 
    var resourceId = req.params.resourceId; 

    Collection.findById(id, function(err, collection) { 
     if (err) { 
      rest.response(req, res, err); 
     } else { 
      var subdoc = collection[resource].id(resourceId); 

      // set the data for each key 
      _.each(data, function(d, k) { 
       subdoc[k] = d; 
      }); 

      collection.save(function (err, docs) { 
       rest.response(req, res, err, docs); 
      }); 
     } 
    }); 
} 

parlak kısmı bu alt belge için Schema tanımlarsanız firavunfaresi data doğrular olduğunu updateSet() yöntemi:

Birincisi, bu yolu var. Bu kod, bir dizi olan belgenin herhangi bir kaynağı için geçerli olacaktır. Tüm verilerimi basitlik için göstermiyorum, ancak bu durumları kontrol etmek ve yanıt hatasını doğru şekilde ele almak iyi bir uygulamadır.

1

Katıştırılmış belgeyi atayabilir veya genişletebilirsiniz.

Doc.findOne({ _id: docId }) 
    .then(function (doc) { 
     if (null === doc) { 
     throw new Error('Document not found'); 
     } 

     return doc.embeded.id(ObjectId(embeddedId)); 
    }) 
    .then(function(embeddedDoc) { 
     if (null === embeddedDoc) { 
     throw new Error('Embedded document not found'); 
     } 

     Object.assign(embeddedDoc, updateData)); 
     return embeddedDoc.parent().save(); 
    }) 
    .catch(function (err) { 
     //Do something 
    }); 

Ve bu durumda, _id'in atamadığından emin olmalısınız.

0

Bunu $ set nesnesini kullanmadan biraz farklı bir şekilde ele aldım. Benim yaklaşımım, Guilherme'ye benziyor, ancak bir fark benim yöntemimi statik işlevselliğe aktarmamdır, böylece uygulamamda yeniden kullanımı daha kolay olur. Aşağıdaki örnek.

CollectionSchema.js sunucu modelinde. Sunucu Denetleyici olarak

collectionSchema.statics.decrementsubdocScoreById = function decreasesubdoc (collectionId, subdocId, callback) { 
    this.findById(collectionId, function(err, collection) { 
    if (err) console.log("error finding collection"); 
    else { 
     var subdoc = collection.subdocs.filter(function (subdoc) { 
     return subdoc._id.equals(subdocId); 
     })[0]; 

     subdoc.score -= 1; 

     collection.save(callback); 
    } 
    }); 
}; 

Collection.decrementsubdocScoreById(collectionId, subdocId, function (err, data) { 
    handleError(err); 
    doStuffWith(data); 
}); 
İlgili konular