0

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

7
  • If "in_reply_to" does not have a direct relation to an original document then you will not be able to do this. You can look at $first as an option to get the "first" matching document to each grouping. Commented Jun 17, 2014 at 14:53
  • Thanks for the comment, but I do an update to the first message to set its in_reply_to to its own _id. Not cute but its one cleaner way of creating conversations of messages. Commented Jun 17, 2014 at 23:09
  • Sounds like you want the "thread" of messages that all have the same in reply to. Some sample data here would help people understand. Commented Jun 17, 2014 at 23:27
  • Sure, heres the current query and and mongo export: codeshare.io/wPObP Commented Jun 17, 2014 at 23:45
  • So what is it that you want? I see two sets of 4 messages with the same "in_reply_to". Do you just want those messages returned "attached" to the "in_reply_to" value? Commented Jun 18, 2014 at 0:13

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

2 Comments

That just returns: [ { _id: { $id: "53a03d43b3f7e236470041a8" }, message: "message", to_user: "to_user", from_user: "from_user" }, { _id: { $id: "53a03cbdb3f7e2e8350041bb" }, message: "message", to_user: "to_user", from_user: "from_user" } ], 1 ],
@azz0r - sorry it was late and I forgot to add $ when writing field names in the query. Now it's fixed :)

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.