sum query mongodb php - php

I have this collection
> db.test.find()
{ "_id" : ObjectId("5398ddf40371cdb3aebca3a2"), "name" : "ahmed", "qte" : 30 }
{ "_id" : ObjectId("5398de040371cdb3aebca3a3"), "name" : "demha", "qte" : 35 }
{ "_id" : ObjectId("5398de140371cdb3aebca3a4"), "name" : "ahmed", "qte" : 50 }
{ "_id" : ObjectId("5398de210371cdb3aebca3a5"), "name" : "ahmed", "qte" : 60 }
i would like to sum "qte" where "name"= "ahmed" and print the sum with php
i know how to do with SQL but i have no idea how it is in mongodb.
Thanks :)

Use the aggregation framework.
Assuming you have an the current collection as $collection
result = $collection->aggregate(array(
array(
'$match' => array(
'name' => 'ahmed'
)
),
array(
'$group' => array(
'_id' => NULL,
'total' => array(
'$sum' => '$qte'
)
)
)
));
The two parts are the $match to meet the criteria, and the $group to arrive at the "total" using $sum
See other Aggregation Framework Operators and the Aggregation to SQL Mapping chart for more examples.

This is done with an aggregate statement:
db.test.aggregate([
{
$match: {
name: "ahmed"
}
},
{
$group: {
_id:"$name",
total: {
$sum: "$qte"
}
}
}
])

Related

Substr in mongodb aggregate in PHP

I have the following command line mongodb query:
db.getCollection('Data').aggregate([
{'$project' : {"_id":"$_id",
"g":"$g",
"value": {'$substr':["$g",0,4]},
}
}])
The result of this query is:
{
"result" : [
{
"_id" : NumberLong(1),
"g" : "1383,09,1,2000",
"value" : "1383"
},
{
"_id" : NumberLong(2),
"g" : "1499,06,1,1",
"value" : "1499"
},
],
"ok" : 1.0000000000000000,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("564d7df200e15758444e9a7d")
}
}
Now I want to use this query in a php file.
Especially how can I use $substr within $project with aggregate in PHP?
You need to use the MongoCollection::aggregate method
$pipeline = array(
'$project' => array(
'g' => '$g',
'value' => array('$substr' => array('$g', 0,4))
)
);
$results = $collection->aggregate($pipeline)

mongodb php query in documents with nested objects

So here is a sample of a document in my mongodb collection:
{
"_id" : ObjectId("561e0de61c9218b7bf9877c3"),
"Date" : NumberLong(20151014),
"Hour" : NumberLong(10),
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ProductName" : "Test",
"ProducerId" : ObjectId("5617802151f8adf4db329d52"),
"ProducerName" : "Producer",
"ProducerRate" : NumberLong(300),
"ProducerMedium" : "Emailer",
"TotalLead" : NumberLong(6),
"VerifiedLead" : NumberLong(3),
"UnverifiedLead" : NumberLong(2),
"UnQualifiedLead" : NumberLong(1),
"TotalEarning" : NumberLong(660),
"Consumers" : [
{
"ConsumerId" : ObjectId("5617802151f8adf4db329d54"),
"ConsumerName" : "Consumer1",
"ConsumedRate" : NumberLong(120),
"ConsumedLead" : NumberLong(3),
"Earning" : NumberLong(360)
},
{
"ConsumerId" : ObjectId("5617802151f8adf4db329d58"),
"ConsumerName" : "Consumer2",
"ConsumedRate" : NumberLong(100),
"ConsumedLead" : NumberLong(3),
"Earning" : NumberLong(300)
}
]
}
Now i want to get the ConsumedLead grouped by ConsumerId and ProductId from the database in php.
what i have did so far to give me TotalLead and VerifiedLead grouped by product id but have no idea how to get consumerbased results for same:
$keyf = new MongoCode('function(doc) {
return {\'ProductId\': doc.ProductId,\'ProductName\': doc.ProductName};
}');
$initial = array('TotalLead'=>0,'VerifiedLead'=>0);
$reduce = "function(obj, prev) {
prev.TotalLead += obj.TotalLead;
prev.VerifiedLead += obj.VerifiedLead;
}";
$result = $collection->group($keyf, $initial, $reduce);
var_dump($result);
Any Help Please.
EDIT:
expected result wpuld be :
{ [0]=> array(4) { ["ProductId"]=> object(MongoId)#8 (1) { ["$id"]=> string(24) "5614ba9c2e131caa098b4567" } ["ProductName"]=> string(4) "Test" ["ConsumerId"]=> object(MongoId)#8 (1) { ["$id"]=> string(24) "5617802151f8adf4db329d58" } ["ConsumedLead"]=> float(4) } }
The solution is to use the aggregation framework where the operation includes an $unwind operator initial pipeline stage as this will deconstruct the Consumers array field from the input documents and outputs a document for each element. Each output document replaces the array with an element value. This will then make it possible for the $sum group accumulator operator in the $group step to work and thus givies you the required ConsumedLead grouped by ConsumerId and ProductId:
db.collection.aggregate([
{
"$unwind": "$Consumers"
},
{
"$group": {
"_id": {
"ProductId": "$ProductId",
"ConsumerId": "$Consumers.ConsumerId"
},
"TotalConsumedLead": {
"$sum": "$Consumers.ConsumedLead"
}
}
}
])
Running this aggregation operation on the above sample will result:
/* 0 */
{
"result" : [
{
"_id" : {
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ConsumerId" : ObjectId("5617802151f8adf4db329d58")
},
"TotalConsumedLead" : NumberLong(3)
},
{
"_id" : {
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ConsumerId" : ObjectId("5617802151f8adf4db329d54")
},
"TotalConsumedLead" : NumberLong(3)
}
],
"ok" : 1
}
So your final working aggregation in PHP should be:
$pipeline = array(
array('$unwind' => '$Consumers'),
array(
'$group' => array(
'_id' => array(
'ProductId' => '$ProductId',
'ConsumerId' => '$Consumers.ConsumerId',
),
'TotalConsumedLead' => array(
'$sum' => '$Consumers.ConsumedLead'
),
)
),
);
$out = $collection->aggregate($pipeline ,$options);

how to aggregate mongodb collection data in laravel

i have collection like this
{
"wl_total" : 380,
"player_id" : 1241,
"username" : "Robin",
"hand_id" : 292656,
"time" : 1429871584
}
{
"wl_total" : -400,
"player_id" : 1243,
"username" : "a",
"hand_id" : 292656,
"time" : 1429871584
}
as both collection have same hand_id i want to aggregate both these collection on the basis of hand_id
i want result as combine of
data=array(
'hand_id'=>292656,
'wl_total'=>
{
0=>380,
1=>-400
},
'username'=>
{
0=>"Robin",
1=>"a"
},
"time"=>1429871584
)
You basically want a $group by the "hand_id" common to all players, and then $push to different arrays in the document and then also do something with "time", I took $max. Nees to be an accumulator of some sort at any rate.
Also not sure what your underlying collection name is, but you can call this in laravel with a construct like this:
$result = DB::collection('collection_name')->raw(function($collection)
{
return $collection->aggregate(array(
array(
'$group' => array(
'_id' => '$hand_id',
'wl_total' => array(
'$push' => '$wl_total'
),
'username' => array(
'$push' => '$username'
),
'time' => array(
'$max' => '$time'
)
)
)
));
});
Which returns output ( shown in json ) like this:
{
"_id" : 292656,
"wl_total" : [
380,
-400
],
"username" : [
"Robin",
"a"
],
"time" : 1429871584
}
Personally I would have gone for a single array with all the infomation in it for the grouped "hand", but I supose you have your reasons why you want it this way.

MongoDB groupby distinct sort together

i have mongodb 1 collections structure like this-
{
"_id" : ObjectId("54d34cb314aa06781400081b"),
"entity_id" : NumberInt(440),
"year" : NumberInt(2011),
}
{
"_id" : ObjectId("54d34cb314aa06781400081e"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2007),
}
{
"_id" : ObjectId("54d34cb314aa06781400081f"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2008),
}
{
"_id" : ObjectId("54d34cb314aa067814000820"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2009),
}
{
"_id" : ObjectId("54d34cb314aa067814000827"),
"entity_id" : NumberInt(489),
"year" : NumberInt(2009),
}
so in output i want that i should get "entity_id" with max "year" only .(suppose with "488" entity_id "year" should be 2009).
i have tried writing query
$fin_cursor = $db->command(array(
"distinct" =>"Profit_and_Loss",
"key" =>'entity_id',
"query" => array(array('$and'=>$financial_pl_search_array),array('$sort'=>array("year"=>-1))),
));
in output i want 2 fields "entity_id" and "year".
can anyone suggest me best way of doing it.
Thanks in advance.
You're better of using .aggregate() to do this. It's also a direct method on the collection objects in modern versions of the driver:
$result = $db->collection('Profit_and_loss')->aggregate(array(
array( '$group' => array(
'_id' => '$entity_id',
'year' => array( '$max' => '$year' )
))
));
The .distinct() command only runs over a single field. Other forms require JavaScript evaluation as you have noted and run considerably slower than native code.

PHP & MongoDB show results grouped by date

I have an mongodb collection with following documents:
{
"_id" : ObjectId("547af6aea3f0eba7148b4567"),
"check_id" : "f5d654e7-257d-4a93-ae50-2d59dfeeb451",
"chunks" : NumberLong(200),
"num_hosts" : NumberLong(1000),
"num_rbls" : NumberLong(163),
"owner" : NumberLong(7901),
"created" : ISODate("2014-11-30T10:51:26.924Z"),
"started" : ISODate("2014-11-30T10:51:31.558Z"),
"finished" : ISODate("2014-11-30T10:57:08.512Z")
}
{
"_id" : ObjectId("54db19a858a5d395a18b4567"),
"check_id" : "9660e510-1349-43f3-9d5e-8bf4b06179be",
"chunks" : NumberLong(2),
"num_hosts" : NumberLong(10),
"num_rbls" : NumberLong(166),
"owner" : NumberLong(7901),
"created" : ISODate("2015-02-11T08:58:17.118Z"),
"started" : ISODate("2015-02-11T08:58:18.78Z"),
"finished" : ISODate("2015-02-11T08:58:47.486Z")
}
{
"_id" : ObjectId("54db267758a5d30eab8b4567"),
"check_id" : "9660e510-1349-43f3-9d5e-8bf4b06179be",
"chunks" : NumberLong(2),
"num_hosts" : NumberLong(10),
"num_rbls" : NumberLong(166),
"owner" : NumberLong(7901),
"created" : ISODate("2015-02-11T09:52:55.388Z"),
"started" : ISODate("2015-02-11T09:52:56.109Z"),
"finished" : ISODate("2015-02-11T09:53:22.095Z")
}
What I need is to get the result and produce an array similar to this:
Array
(
[2015-02-11] => array
(
//array with results from 2015-02-11
)
[2014-11-30] => array
(
//array with results from 2014-11-30
)
)
I know that it's possible to just perform simply collection->find and then loop through results and use php logic to achieve my goal but is it possible to make it using mongo? Maybe using aggregation framework?
EDIT: I want to group results by "created" date
Any help will be highly appreciated.
Monogo aggregation mongo aggregation group used for this, so below query may solve your problem
db.collectionName.aggregate({
"$group": {
"_id": "$created",
"data": {
"$push": {
"check_id": "$check_id",
"chunks": "$chunks",
"num_hosts": "$num_hosts",
"num_rbls": "$num_rbls",
"owner": "$owner",
"started": "$started",
"finished": "$finished"
}
}
}
}).pretty()
Or
db.collectionName.aggregate({
"$group": {
"_id": "$created",
"data": {
"$push": "$$ROOT"
}
}
}).pretty()
Also in mongo 2.8 $dateToString provide facility to convert ISO date to string format so below query also work
db.collectionName.aggregate([
{
"$project": {
"yearMonthDay": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$created"
}
},
"check_id": "$check_id",
"chunks": "$chunks",
"num_hosts": "$num_hosts",
"num_rbls": "$num_rbls",
"owner": "$owner",
"started": "$started",
"finished": "$finished"
}
},
{
"$group": {
"_id": "$yearMonthDay",
"data": {
"$push": "$$ROOT"
}
}
}
]).pretty()
I have managed to solve this using the aggregation framework. Here is the answer, in case anyone need it.
$op = array(
array(
'$project' => array(
'data' => array(
'check_id' => '$check_id',
'chunks' => '$chunks',
'num_hosts' => '$num_hosts',
'num_rbls' => '$num_rbls',
'owner' => '$owner',
'started' => '$started',
'finished' => '$finished',
),
'year' => array('$year' => '$created' ),
'month' => array('$month' => '$created' ),
'day' => array('$dayOfMonth' => '$created'),
)
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'reports_data' => array('$push' => '$data'),
)
),
);
$c = $collection->aggregate($op);

Categories