2

I would like to mark all messages as read by 'jim'. Here is the structure of a thread:

db.threads.save({
    messages: [
        {
            read_by: ['bob', 'jim']
        },
        {
            read_by: ['bob']
        },
        {
            read_by: ['bob']
        }
    ]
})

As you can see, one message has already been read by 'jim', the rest only by 'bob'. I'd like to find and modify any embedded documents so that 'jim' is appended to the read_by array.

Here is where I got:

db.threads.findAndModify({
    query: {
        'messages.read_by': {
            $ne: 'jim'
        }
    },
    update: {
        $push: {
            'messages.$.read_by': 'jim'
        }
    }
})

I get this error:

uncaught exception: findAndModifyFailed failed: "can't append to array using string field name [$]"

The query works with a db.threads.find() so I guess the problem is with the update part of the findAndModify() call.

DrPheltRight
  • 85
  • 3
  • 9
  • Try this, ... update: { $push: { 'messages.read_by': 'jim' } }... Being read_by an element inside an array you can access it directly. – reixa Mar 14 '13 at 11:39
  • Yeah this doesn't work unfortunately. It appears you can't $push to embedded document arrays. – DrPheltRight Mar 14 '13 at 12:20

2 Answers2

2

I know its been a while, but pushes into nested documents is indeed possible. You need to add an each into it. For example,

db.threads.update({
    'messages.read_by': {
        $ne: 'jim'
    }
},
{
    $push: {
        'messages.read_by': {
            $each: ['jim']
        }
    }
}
)

See here for more samples - http://docs.mongodb.org/manual/reference/operator/update/push/

Even though you are just passing only one value, for nested arrays, you need to pass $each. If the document already contains a read_by field with some values in it, then an update without the each works. Using the $each will work irrespective of whether the field exists or not.

etrast81
  • 280
  • 1
  • 4
  • 16
1

With one operation, you can't do this yet. See this question, which is the same as yours.

You will have to this sort of operation in your application: find() all messages which jim has not already read, append him to them, and then set the messages field of your thread to this array.

Community
  • 1
  • 1
gustavohenke
  • 40,997
  • 14
  • 121
  • 129