61

I have this mongoose schema

var mongoose = require('mongoose');

var ContactSchema = module.exports = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  phone: {
    type: Number,
    required: true,
    index: {unique: true}
  },
  messages: [
  {
    title: {type: String, required: true},
    msg: {type: String, required: true}
  }]
}, {
    collection: 'contacts',
    safe: true
});

and trying to update the model by doing this:

Contact.findById(id, function(err, info) {
    if (err) return res.send("contact create error: " + err);

    // add the message to the contacts messages
    Contact.update({_id: info._id}, {$push: {"messages": {title: title, msg: msg}}}, function(err, numAffected, rawResponse) {
      if (err) return res.send("contact addMsg error: " + err);
      console.log('The number of updated documents was %d', numAffected);
      console.log('The raw response from Mongo was ', rawResponse);

    });
  });

I'm I not declaring the messages to take an array of objects?
ERROR: MongoError: Cannot apply $push/$pushAll modifier to non-array

Any ideas?

15
  • What error message are you getting? What do you mean by "I can't seem to get the $push done right"? Commented Mar 25, 2013 at 18:36
  • MongoError: Cannot apply $push/$pushAll modifier to non-array Commented Mar 25, 2013 at 18:37
  • 1
    Not sure if this will fix it, but try taking away the square brackets from around [{title: title, msgs: [msg]}]. $push takes in a single value. Commented Mar 25, 2013 at 18:39
  • 1
    My guess is you are initially adding the messages as a non-array Commented Mar 25, 2013 at 19:11
  • 1
    @user1460015 Please mark your question as solved. Commented Jun 10, 2013 at 18:40

2 Answers 2

127

mongoose does this for you in one operation.

Contact.findByIdAndUpdate(
    info._id,
    {$push: {"messages": {title: title, msg: msg}}},
    {safe: true, upsert: true},
    function(err, model) {
        console.log(err);
    }
);

Please keep in mind that using this method, you will not be able to make use of the schema's "pre" functions.

http://mongoosejs.com/docs/middleware.html

As of the latest mogoose findbyidandupdate needs to have a "new : true" optional param added to it. Otherwise you will get the old doc returned to you. Hence the update for Mongoose Version 4.x.x converts to :

Contact.findByIdAndUpdate(
        info._id,
        {$push: {"messages": {title: title, msg: msg}}},
        {safe: true, upsert: true, new : true},
        function(err, model) {
            console.log(err);
        }
    );
Sign up to request clarification or add additional context in comments.

8 Comments

@TejasManohar its just to show that you can have multiple options included there.
this answer helped me a lot. But what's with those options, safe, upsert and new?
"new" - so that you get the updated document in return (read answer description) "upsert" - Optional. If set to true, creates a new document when no document matches the query criteria. The default value is false, which does not insert a new document when no match is found. docs.mongodb.org/manual/reference/method/db.collection.update "safe" - stackoverflow.com/questions/4974686/…
what's info._id, is it a string or an ObjectId ?
safe is not included in the documentation for .findOneAndUpdate()
|
8

there are two ways for pushing data in array

first way:

let newMessage = {title: "new title", msg: "new Message"}
let result = await Contact.findById(id);
result.messages.push(newMessage);
await result.save();

second way

let result = await Contact.findByIdAndUpdate(
        id,
        {$push: {"messages": {title: title, msg: msg}}},
        {upsert: true, new : true})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.