Partial update of a subdocument with nodejs/mongoose

后端 未结 4 1956
情话喂你
情话喂你 2020-12-08 08:36

Is it possible to set multiple properties on a (sub)document in one go with Mongoose? An example of what I\'m trying to do:

Let\'s say I have this schema:

         


        
相关标签:
4条回答
  • 2020-12-08 09:15

    I've done different, in a REST application.

    First, I have this route:

    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);
    });
    

    and the updateSet() method

    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);
                });
            }
        });
    }
    

    The brilliant part is mongoose will validate the data if you define the Schema for this subdocument. This code will be valid for any resource of the document that is an Array. I'm not showing all my data for simplicity, but is a good practice to check for this situations and handle the response error properly.

    0 讨论(0)
  • 2020-12-08 09:23

    You can assign or extend embedded document.

        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
        });
    

    And in this case you should be shure that _id is not assigning.

    0 讨论(0)
  • 2020-12-08 09:29

    Build up a $set object programmatically based on the fields of partialUpdate to update just those fields using dot notation:

    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 讨论(0)
  • 2020-12-08 09:30

    I handled this in a slightly different manner without using the $set object. My approach is similar to Guilherme's but one difference is that I wrapped my method into the statics functionality so that it is easier to re-use throughout my application. Example below.

    In CollectionSchema.js server model.

    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);
        }
      });
    };
    

    In Server Controller

    Collection.decrementsubdocScoreById(collectionId, subdocId, function  (err, data) {
      handleError(err);
      doStuffWith(data);
    });
    
    0 讨论(0)
提交回复
热议问题