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,

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.

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.

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.