14

I have the following mongodb object:

{
 "_id": ObjectId("4d0b9c7a8b012fe287547157"),
 "messages": {
 "0": {
 "toUname": "Eamorr3",
 "fromUname": "Eamorr2",
 "time": 1292606586,
 "id": "ABCDZZZ",
 "subject": "asdf",
 "message": "asdf",
 "read": 0 //I want to change this to 1!
 },
 "1": {
 "toUname": "Eamorr1",
 "fromUname": "Eamorr3",
 "time": 1292606586,
 "id": "EFGHZZZ",
 "subject": "asdf2",
 "message": "asdf2",
 "read": 0
 }
 },
 "uname": "Eamorr3"
}

How do I set "read" to 1 where id=ABCDZZZZ? I'm using PHP.

I've tried the following command:

$driverInboxes->update(array('uname'=>$uname),array('$set'=>array('messages'=>array('id'=>$id,'read'=>'1'))));

But when I do this, overwriting occurs and I get:

{
 "_id": ObjectId("4d0b9c7a8b012fe287547157"),
 "messages": {
 "id": "j7zwr2hzx14d3sucmvp5",
 "read": "1"
 },
 "uname": "Eamorr3"
}

I'm totally stuck. Any help much appreciated.

Do I need to pull the entire array element, modify and and push it back in again?

Many thanks in advance,

Eran Medan
45.9k61 gold badges187 silver badges283 bronze badges
asked Dec 17, 2010 at 18:38
2

2 Answers 2

17

If you read your command, you're actually saying: "UPDATE WHERE uname = Eamorr3 SET messages equal to this array (id=blah,read=1)"

When you do a $set on messages, you're basically instructing it to take your array as the new value.

However, it looks like you're trying to update a specific message as read which is just a little more complex. So there are two hurdles here:

1: You're actually updating messages.0.read

If you do array('$set' => array( 'messages.0.read' => 1 ) ), you will update the correct element. Follow that chain, messages is a javascript object and you want to update the property 0. The property 0 is itself a javascript object which contains the property read which you want to update.

Can you see how you're updating messages.0.read?

This brings us to problem #2.

2: the 0 is a problem for you

If you look at the way you've structured the data in Mongo, the messages object is really sub-par. The "0" and "1" are currently acting as "ids" and they're not very useful. Personally, I would structure your objects with the actual IDs in place of "0" or "1".

So your objects would look like the following:

{
 "_id": ObjectId("4d0b9c7a8b012fe287547157"),
 "messages": {
 "ABCDZZZ": {
 "toUname": "Eamorr3",
 "fromUname": "Eamorr2",
 "time": 1292606586,
 "subject": "asdf",
 "message": "asdf",
 "read": 0 //I want to change this to 1!
 }
 },
 "uname": "Eamorr3"
}

Now you're update command becomes this:

array('$set' => array( 'messages.ABCDZZZ.read' => 1 ) )

This structure makes it much easier to update a specific message or a specific portion of a message.

answered Dec 17, 2010 at 19:25
Sign up to request clarification or add additional context in comments.

2 Comments

Hey, I was thinking of restructuring like the way you mentioned. I think this is probably the best way to go. Otherwise, I'm going to have to look through the entire array, find the object index, and update.
Also take a look at $elemMatch
3

If you want to keep the array structure for various purposes, you can use the Positional operator. This enables you to take advantage of array features ($pop,$push,etc) while simultaneously being able to update elements which are in an unknown array position.

answered Jun 23, 2011 at 19:26

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.