如何在PHP中使用MongoDB中的“group”?

I'm using PHP with MongoDB, How can apply below commend inside?

db.event.group({
    keyf: function(doc) {
        return { 
            year: doc.created.getFullYear(),
            month: doc.created.getMonth() + 1,
            day: doc.created.getDate()
        }
    },
    reduce: function(curr, result){
        result.count++;
   },
    initial: {count: 0}
});

I have tried below, but NOT working. Looks like not supprt keyf?

$keyf = 'function(doc){return {year: doc.created.getFullYear(), month: doc.created.getMonth()+1, day: doc.created.getDate()}}';
$initial = array('count' => 0);
$reduce = 'function(curr, result){result.count++;}';
$collection->group($keyf, $initial, $reduce);

It looks like you are basically counting the amount of documents under a date.

It should be noted that the group command has numerous flaws including:

  • Not officially supporting sharding (warning not to use it)
  • Is basically JavaScript
  • Is Basically a Map Reduce
  • Is extremely slow

that means it has since been "deprecated" in favour of the aggregation framework, which in PHP for you would be:

$db->collection->aggregate(array(
    array('$group' => array(
        '_id' => array(
             'day' => array('$dayOfMonth' => '$created'),
             'month' => array('$month' => '$created'),
             'year' => array('$year' => '$created')
         ),
         'count' => array('$sum' => 1)
    ))
));

To understand what operators I used etc you can look here:

The PHP driver does have the MongoCode class for constructing the JavaScript values that are required.

But you are actually better off using the .aggregate() command to this as it is "native* code and does not rely on the JavaScript engine. So it is much faster at producing results.

db.collection.aggregate([
    { "$group": {
        "_id": {
           "year": { "$year": "$created" },
           "month": { "$month": "$created" },
           "day": { "$dayOfMonth": "$created" }
        },
        "count": { "$sum": 1 }
    }}
])

Data Problem


So the aggregate function works are expected, but you seem to have a problem with your test data. Here is cwhat you gave:

db.post.insert({'field':'b', 'created':new Date('2014, 1, 1')});
db.post.insert({'field':'c', 'created':new Date('2014, 1, 1 11:11:11')});
db.post.insert({'field':'d', 'created':new Date('2014, 1, 1 12:00:00')});
db.post.insert({'field':'a', 'created':new Date('2014, 1, 2')});
db.post.insert({'field':'b', 'created':new Date('2014, 1, 2')})

And this produces the data:

{ "field" : "a", "created" : ISODate("2013-12-31T13:00:00Z") }
{ "field" : "b", "created" : ISODate("2013-12-31T13:00:00Z") }
{ "field" : "c", "created" : ISODate("2014-01-01T00:11:11Z") }
{ "field" : "d", "created" : ISODate("2014-01-01T01:00:00Z") }
{ "field" : "a", "created" : ISODate("2014-01-01T13:00:00Z") }
{ "field" : "b", "created" : ISODate("2014-01-01T13:00:00Z") }

So it looks like you were trying to add "hours" in the same day to test the grouping. But the arguments to Date() are not correct. You wanted this:

db.post.insert({'field':'b', 'created':new Date('2014-01-01')});
db.post.insert({'field':'c', 'created':new Date('2014-01-01 11:11:11')});

So the whole date as a string and not the "comma" separated values