2

I've seen a bunch of the other Mongo PHP $push questions up here on SO, but for some reason none of what they're saying is working, so I'm posting my own version.

Basically, I'm trying to follow a guideline set by 10gen where representing something like a news feed or blog/comment post should be done using buckets - making documents that hold a certain number (50) of events (comments, etc.), and then creating multiple documents as the content grows.

What I'm trying to do is push documents ($event) into an array (events), but there seems to be some confusion with PHP when the document doesn't exist (upserting). I tried to do it with an insert, but insert and $push don't play well together.

Here's what I have right now:

$historyDoc = array('_id'=>$uID, 'count'=>1,
  array('$push' => array('events' => $event)));

$query = array('_id'=>$uID);

//add user to history
$collection->update($query,$historyDoc,
    array('safe'=>true,'timeout'=>5000,'upsert'=>true));

Where $event is a properly-formatted array (document) of things (e.g. timestamp, userID, action, name) and $uID is a MongoID object taken from another collection.

The result that I get is this:

{
"_id": {
    "$oid": "4f77ec39fef97a3965000000"
    },
"0": {
    "$push": {
        "events": {
            "timestamp": 1333259321,
            "action": "achievement",
            "pts": 0,
            "name": "join"
        }
    }
},
"count": 1
}

Which is good, because my document is at least showing up right, but how the hell is there a key with a "$" in it? It's not like I'm failing to escape the $...I've been very intently using single quotes for that exact reason.

Maybe there's something I'm missing, or maybe I broke PHP, but I've been wrestling with this one for awhile and there's nothing I can thing of. It's holding my whole project up, so....>:/

2 Answers 2

1

Your update document is ill-formed, try this:

$historyDoc = array('_id' => $uID, 
                    'count' => 1,
                    '$push' => array('events' => $event));
Sign up to request clarification or add additional context in comments.

3 Comments

Tried that one before. I just did it again, and here's the error message I got: exception 'MongoCursorException' with message 'Modifiers and non-modifiers cannot be mixed' in /var/fog/apps/app34260/trinker.phpfogapp.com/php/register.php:190. I saw something in the PHP Mongo Manual somewhere that looked promising, so I'm gonna try that.
Ah, indeed, you can't mix those. Try converting count to $set. You can't $set an _id, though.
I have a solution but stupid StackOverflow won't let me post it for another 7 hours because I don't have over 100 rep. It's times like these where the reputation system backfires. Screw you, SO. See: my edit for solution
1

It's not the most elegant solution, but it looks like it works. Apparently there's a problem with using $push on a new document (insert or upsert) (EDIT: It might actually be the issue with combining atomic and non-atomic thing that's the problem. You can't use atomic operators on _id, so...). However, you can get around it by inserting the document first and then updating/upserting it.

In order to initialize an array in Mongo via PHP, you need to create a document with an empty array a a value, as seen here:

$historyDoc = array('_id'=>$uID.'-0',
        'count'=>1, 
        'events'=>array());

From there, you can simply take what you were going to put into the first index and upsert it later:

$collection->update($query, $historyDoc,
             array('safe'=>true,'timeout'=>5000,'upsert'=>true));

$collection->update($query,
            array('$push'=>array('events'=>$event)),
            array('safe'=>true,'timeout'=>5000,'upsert'=>true));

This yields a resulting document of the form:

{
"_id": "4f77f307fef97aed12000000-0",
"count": 1,
"events": [
    {
        "timestamp": 1333261063,
        "action": "achievement",
        "pts": 0,
        "name": "join"
    }
]
}

Source: Mongo PHP Manual - Updates

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.