azz0r
azz0r

Reputation: 3311

PHP Mongo Aggregation only returns _id

I am trying to return a collection of messages grouped by in_reply_to field, I have this code:

$result = $this->db->Message->aggregate(
            array(
                array(
                    '$project' => array('message' => 1, 'in_reply_to'=> 1, 'to_user' => 1, 'from_user' => 1)
                ),
                array(
                    '$group' => array('_id' => '$in_reply_to'),
                ),
            )
        );
        print_r($result);exit;

the result is:

Array ( 
    [result] => Array ( 
        [0] => Array ( 
            [_id] => MongoId Object ( 
                [$id] => 53a03d43b3f7e236470041a8 
            ) 
        ) 
        [1] => Array ( 
            [_id] => MongoId Object ( 
                [$id] => 53a03cbdb3f7e2e8350041bb
            ) 
        ) 
   ) 
   [ok] => 1 
)

Ideally I'd like the entire Message object, but I did think that $project would be used to specify returns fields, even so, I dont get the fields I'm specifying.

Any help is greatly appreciated

Upvotes: 0

Views: 799

Answers (2)

Neil Lunn
Neil Lunn

Reputation: 151112

In order to get all the messages in the thread you basically want to $push

$result = $this->db->Message->aggregate(
    array(
        array(
            '$group' => array(
                '_id' => '$in_reply_to',
                'messages' => array(
                    '$push' => array(
                        '_id' => '$_id',
                        'message' => '$message',
                        'to_user' => '$to_user',
                        'from_user' =>'$from_user'
                    )
                )
            )
        )
    )
);

MongoDB 2.6 you have the $$ROOT variable that shortens this:

$result = $this->db->Message->aggregate(
    array(
        array(
            '$group' => array(
                '_id' => '$in_reply_to',
                'messages' => array(
                    '$push' => '$$ROOT'
                )
            )
        )
    )
);

So that puts all of the related messages inside the "messages" array tied to that key.

Just as side note, while you can do this you may as well just sort the results by your "in_reply_to" field and process them that way looking for changes in the value to indicate a new thread.

Sorting with a find would be the fastest way to process, even if it does not conveniently put everything right under the one key.

Upvotes: 2

Christian P
Christian P

Reputation: 12240

If you want to get additional fields beside _id field, when using $group operator, you need to include them using some of the available accummulators like $first or $last. You can see the full list on the MongoDB $group documentation page.

The query will look like this:

$result = $this->db->Message->aggregate(
    array(
        array(
            '$project' => array(
                'message' => 1, 
                'in_reply_to'=> 1, 
                'to_user' => 1, 
                'from_user' => 1
            )
        ),
        array(
            '$group' => array(
                '_id' => '$in_reply_to',
                'message' => array('$first' => '$message'),
                'to_user' => ('$first' => '$to_user'),
                'from_user' => ('$first' => '$from_user')
            ),
        ),
    )
);

If the message, to_user and from_user values are same in all documents using $last instead of $first $last will produce the same results.

Upvotes: 0

Related Questions