48

I need to push multiple values into an array in mongoose using one call. I tried doing it using a smaller array but the array is getting inserted as a sub-array.

var kittySchema = new mongoose.Schema({
        name: String,
        values: [Number]
});

var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$push: {values:[2,3]}},{upsert:true},function(err){
        if(err){
                console.log(err);
        }else{
                console.log("Successfully added");
        }
});

The result of the calling the above code thrice gives the below result:

{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ [ 2, 3 ], [ 2, 3 ], [ 2, 3 ] ] }

Whereas what I want is something like this:

{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ 2, 3 ,2 ,3, 2, 3] }

Another thing I noticed was that the type in the array (values) is specified as Number, then wouldnt the 'strict' option ensure that anything other than Numbers are not inserted ? In this case another array is being allowed to be inserted.

Pranil Dasika
  • 593
  • 1
  • 6
  • 7

4 Answers4

47

(Dec-2014 update) Since MongoDB2.4 you should use:

Kitten.update({name: 'fluffy'}, {$push: {values: {$each: [2,3]}}}, {upsert:true}, function(err){
        if(err){
                console.log(err);
        }else{
                console.log("Successfully added");
        }
});
Amit Portnoy
  • 5,957
  • 2
  • 29
  • 30
  • If no doc with `{name: "fluffy"}` in it exists, does `{upsert: true}` create it?; also, if I do `{upsert: true, new: true}`, can I do function(err, result) {} and get in result all of the documents that were created/updated? – Besto Dec 04 '16 at 17:06
41

Deprecated see other solution below using $push $each

Your example is close, but you want $pushAll rather than $push to have each value added separately (rather than pushing another array onto the values array):

var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$pushAll: {values:[2,3]}},{upsert:true},function(err){
        if(err){
                console.log(err);
        }else{
                console.log("Successfully added");
        }
});
Scott Stensland
  • 26,870
  • 12
  • 93
  • 104
Stennie
  • 63,885
  • 14
  • 149
  • 175
  • 18
    NB: you may also want to look at [$addToSet](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24addToSetand%24each), which can be used to only add values to an array if they aren't there already. – Stennie Aug 15 '12 at 03:39
  • Thanks Stennie! That works. I missed this part in the documentation. – Pranil Dasika Aug 15 '12 at 04:44
  • @Stennie this only works for individual elements, not for concatenating arrays. – Tom Dec 24 '13 at 16:54
  • 2
    @Tom concatenating arrays can be done with $addToSet together with [$each](http://docs.mongodb.org/manual/reference/operator/update/addToSet/#each-modifier). – super-qua Oct 21 '14 at 11:39
5

Or use the $each modifier with $addToSet:

https://docs.mongodb.com/manual/reference/operator/update/addToSet/#each-modifier

// Existing tags array
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }

// Add "camera" and "accessories" to it
db.inventory.update(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "accessories" ] } } }
 )
Dominic
  • 62,658
  • 20
  • 139
  • 163
1

Currently, the updated doc doesn't support $pushAll. It seems to have been deprecated. Now the good choice is to use the combination of $push & $each

an example:

//User schema: {uid: String, transaction: [objects] }
const filter = {"uid": uid};
const update = {
        $push: {
            transactions: {$each: dataarr}
        }
    }
User.updateOne(filter, update, {upsert:true}, (err) => {
        if(err){
            console.log(err)
        }
    })

pass {upsert: true} at options to insert if the filter returns false.

Bisakh Mondal
  • 33
  • 1
  • 5