0

A document in my collection rooms has the following structure:

{
    "_id": { "$oid": "4edaaa4a8d285b9311eb63ab" },

    "users": [
        {
            "userId": { "$oid": "4edaaa4a8d285b9311eb63a9" },
            "unreadMessages": 0
        },

        {
            "userId": { "$oid": "4edaaa4a8d285b9311eb63aa" },
            "unreadMessages": 0
        },
    ]
}

I'd like to increment unreadMessages of the second user (the one at index 1 in the array), if I know the ObjectId of the first user. Knowing the _id of the document is sufficient for selecting, but for updating I need to be able to reference to the other user, so I'm also selecting by users. I'm doing so with the following update call:

collections.rooms.update(
    {
        _id: ObjectId("4edaaa4a8d285b9311eb63ab"),

        users: {           // not first user
            $elemMatch: { $ne: { userId: ObjectId("4edaaa4a8d285b9311eb63a9") } }
        }
    },

    {
        // this should increment second user's unreadMessages,
        // but does so for unreadMessages of first user
        $inc: { "users.$.unreadMessages": 1 }
    }
);

It increments unreadMessages of the first user, not of the second user. I guess this is because $ne actually matches on the first user, and apparently that's what users.$ is referring to.

How should I modify this call so that the second user's unreadMessages is incremented?

pimvdb
  • 151,816
  • 78
  • 307
  • 352

1 Answers1

2

I think you're doing the right thing, except for a little syntax dyslexia around the $ne query constraint.

So where you have

users: {           // not first user
    $elemMatch: { $ne: { userId: ObjectId("4edaaa4a8d285b9311eb63a9") } }
}

instead you want

users: {           // not first user
    $elemMatch: { userId: { $ne: ObjectId("4edaaa4a8d285b9311eb63a9") } }
}

If I had a nickel for every time I've done the same kind of swap ... I'd have a lot of nickels. :)

Actually, if you want to tighten things up, the $elemMatch is not really needed, since you're only constraining one property of the matched array element. I think you can boil the whole query criteria down to:

{
    _id: ObjectId("4edaaa4a8d285b9311eb63ab"),
    users.userId: { $ne : ObjectId("4edaaa4a8d285b9311eb63a9") }
}
dampier
  • 4,996
  • 1
  • 21
  • 18
  • I had to swap indeed. Though, the `$elemMatch` seems necessary since it isn't updating without. Everything is working now, thanks! – pimvdb Dec 04 '11 at 12:03