mbecker
mbecker

Reputation: 1673

MongoDB: How to add or update a SubDocument with Mongoose?

I'm trying to add a new or to update an existing SubDocument based on it's existence.

Given is the following Schema:

var providerSchema = new Schema({
  provider: String,
  id: String,
  accessToken: Object
})

var userSchema = new Schema({
  email: { type: String },
  provider: [providerSchema],
  created_at: Date,
  updated_at: Date
});

The following Document is stored:

    {
    "_id": {
        "$oid": "5629f57b13bc066c17b88a0d"
    },
    "created_at": {
        "$date": "2015-10-23T08:53:15.684Z"
    },
    "updated_at": {
        "$date": "2015-10-23T08:53:15.684Z"
    },
    "email": "[email protected]",
    "provider": [
        {
            "provider": "facebook",
            "id": "123123",
            "accessToken": {
                "expires_in": 123123,
                "token_type": "bearer",
                "access_token": "123123123"
            },
            "_id": {
                "$oid": "5629f57b13bc066c17b88a0e"
            }
        },
        {
            "accessToken": {
                "access_token": "123123",
                "token_type": "bearer",
                "uid": "123123"
            },
            "id": "123123",
            "provider": "dropbox",
            "_id": {
                "$oid": "5629f58813bc066c17b88a12"
            }
        }
    ],
    "__v": 0
}

I'm trying to update or to add the new SubDocument with the following code:

User.findOneAndUpdate({email: email},
    {
      "$push" : {
        "provider": {
          "provider": "dropbox",
          "id": "123441212",
          "accessToken": "sdasddad"
        }
      }
    },  function (error, doc) { 
         .... 
}});

Unfortunately the existing SubDocuments aren't updated but new SubDocuments are created.

Could you please help me?

Thanks in advance!

P.s. Is it possible to have named SubDocuments? So for example to have a SubDocument called "facebook" which is accessible directly via name?

--- Solution ---

User.findOne(
    {"email": email})
    .populate("provider")
    .exec(function (err, data) {
        if(data === null && typeof data === "object"){
          // Create User
          user.save(function (error) {
            if(error) return callback(new Error(error), null);
            return callback(null, user);
          })
        } else {
          //
          if(err) return callback(new Error(err), null);

          var prov = _.findWhere(data.provider, { "provider": provider });

          if(typeof variable_here === 'undefined'){
              data.provider.push(update);
          } else {
            _.extend(prov, update);
          }

          data.save(function (error) {
            if(error) {
              return callback(error, null);
            } else {
              return callback(null, data);
            }
          });
        }
      }
    );

Thanks, Hossein Gerami! Still a lot of fallbacks ...

(I struggled at first with "_.findWhere"; it's underscore; just install via "npm install underscore --save" and put the following line in your file "var _ = require('underscore');")

Upvotes: 3

Views: 2690

Answers (3)

mbecker
mbecker

Reputation: 1673

--- Solution ---

User.findOne(
    {"email": email})
    .populate("provider")
    .exec(function (err, data) {
        if(data === null && typeof data === "object"){
          // Create User
          user.save(function (error) {
            if(error) return callback(new Error(error), null);
            return callback(null, user);
          })
        } else {
          //
          if(err) return callback(new Error(err), null);

          var prov = _.findWhere(data.provider, { "provider": provider });

          if(typeof variable_here === 'undefined'){
              data.provider.push(update);
          } else {
            _.extend(prov, update);
          }

          data.save(function (error) {
            if(error) {
              return callback(error, null);
            } else {
              return callback(null, data);
            }
          });
        }
      }
    );

Thanks, Hossein Gerami! Still a lot of fallbacks ...

(I struggled at first with "_.findWhere"; it's underscore; just install via "npm install underscore --save" and put the following line in your file "var _ = require('underscore');")

Upvotes: 0

Alok Deshwal
Alok Deshwal

Reputation: 1126

Consider the following document in the students collection whose grades element value is an array of embedded documents:

    {
      _id: 4,
      grades: [
         { grade: 80, mean: 75, std: 8 },
         { grade: 85, mean: 90, std: 5 },
         { grade: 90, mean: 85, std: 3 }
      ]
    }

Use the positional $ operator to update the value of the std field in the embedded document with the grade of 85:

    db.students.update(
       { _id: 4, "grades.grade": 85 },
       { $set: { "grades.$.std" : 6 } }
    )

Below code is the complete syntax for update in the following if you define upsert as true it will insert new record other wise it will be updated. Default Value : false

            db.collection.update(
               <query>,
               <update>,
               {
                 upsert: <boolean>,
                 multi: <boolean>,
                 writeConcern: <document>
               }
            )

Upvotes: 1

Ketha Kavya
Ketha Kavya

Reputation: 588

You can try this. I think this may work.

 User.update({email: email,provider.provider:'dropbox'},{$set:{"provider.$": {"provider": {
              "provider": "dropbox",
              "id": "123441212",
              "accessToken": "sdasddad"
            }}}},function(error, doc){
    ...
    }});

Upvotes: 0

Related Questions