MongoDB PHP Aggregating data with condition - php

I have 2 different pipelines: with condition
$pipeline = array(
array('$match' => array(
'currentStep' => 'CREATE')),
array('$group' => array(
'_id' => '$name',
'value' => array('$sum' => 1)
)));
and without
$pipeline = array(
array('$group' => array(
'_id' => '$name',
'value' => array('$sum' => 1)
)));
How combine them in one single $pipeline in order to get such output:
_id - value_with_match_condition - value_without

In order to do this, you will need to combine the use of $sum with $cond. For instance, it might look something like this:
$pipeline = array(
array('$group'=>array(
'_id'=>'$name',
'sum_matching'=>array(
'$sum'=>array('$cond'=>array(
'if'=>array('$eq'=>array('$currentStep', 'CREATE')),
'then'=>1,
'else'=>0
)),
),
'sum_all'=>array('$sum'=>1)
))
);
This is untested, but something matching this general form should work.

Related

How to subtract in mongodb php

$getdataPipeline = array(
array(
'$match' => array(
'project_id' => array('$in' => $mysql_project_id) // Validating project ID
),
'$match' => array('project_id' => $project_id)
),
array(
'$group' => array(
'_id' => array('pro_id' => '$project_id', 'uid' => '$user_id'),
"wh" => array('$subtract' => array(array('$sum' => '$toltal_timein_minutes'), array('$sum' => '$holding_durationin_minutes')))
))
);
Running query:
$ValidProjectIdInMongo = $collection->aggregate($getdataPipeline);
I'm getting an error like
Uncaught exception 'MongoResultException' with message 'localhost:27017: exception: unknown group operator '$subtract''
The $sum is the accumulator to be used with $group, so it must be the top level operator used. Therefore your other operations need to happen "inside" the $sum:
$getdataPipeline = array(
array(
'$match' => array('project_id' => $project_id)
),
array(
'$group' => array(
'_id' => array('pro_id' => '$project_id', 'uid' => '$user_id'),
"wh" => array(
'$sum' => array(
'$subtract' => array(
'$toltal_timein_minutes',
'$holding_durationin_minutes'
)
)
)
)
)
);
You can do it here because this is basic subtraction, but more complex operations would generally require a separate $project stage after the $group.
Also note that yout $match pipeline stage is incorrect and will actually be interpretted just as I have re-written above. You perhaps mean in $in condition for both the possible values, which is a logical $or.
You also have what looks like typing errors in the field names.

to get sum in multiple conditions in mongodb and php

I've the following code to get the some of all price that have type 1 or a specific value but it dosen't work.
<?php
$m = new Mongo();
if (!$m)echo "Not Connected to database successfully";
$db =$m->mongo_project;
$collection = $db->prices;
$pipeline=array(
array(
'$match' => array(
'_id' => array(
'$type' =>1
)
)
),
array(
'$group' => array(
'_id' => '',
'count' => array(
'$sum' => '$price'
)
)
),
);
$out = $collection->aggregate($pipeline);
foreach ($out as $key=>$value) {
if($key=='result') {
$r=$value[0]['count'];
}
}
echo $r;?>
I think you mean a document that has a field "type" with a value of 1. The $type operator used here is a special MongoDB operator used to match certain BSON types. In this case you were asking for matching _id fields that were a "DOUBLE" type, or BSON type 1.
Correcting this:
$pipeline=array(
array(
'$match' => array(
'type' => 1
)
),
array(
'$group' => array(
'_id' => '',
'total' => array(
'$sum' => '$price'
)
)
),
);
Or you could just get the "sum" of the "price" values per each "type" value by passing that as the _id in your $group operation, instead. That way you can see everything at a glance:
$pipeline=array(
array(
'$group' => array(
'_id' => '$type',
'total' => array(
'$sum' => '$price'
)
)
),
);
In that context, '$type` means the value of the field.

add second parameter to $match in mongoDB

I have some collection
**name lastname status**
Jack Nons "no"
Toni Griffon "no"
Anna Griffon "no"
Alex Maxvel "yes"
Nina Maxvel "yes"
I want to recieve the lastnames, which is not unique and where status is "yes".
My code wrote in php and I recieved all not unique lastnames but don't check status.
$cursor = $collection->aggregate(
array(
array(
'$group' => array("_id" => array('lastname' => '$lastname'), 'total' => array('$sum' => 1)
)
),
array(
'$match' => array('total' => array('$gt' => 1)
),
)
)
);
Please tell me how to add checking of status?
You can have multiple $match stages in the aggregation pipeline and multiple conditions in one $match operator.
It would be would faster to first filter documents that have 'status' == 'yes' and then to group them. The $group operation will then have less documents to process:
$collection->aggregate(array(
array(
array(
'$match' => array('status' => 'yes'),
),
array(
'$group' => array(
"_id" => array('lastname' =>'$lastname'),
'total' => array('$sum' => 1)
)
)
)
);
You can put more than one condition into match.
'$match' => array('total' => array('$gt' => 1), 'status' => 'yes')

How to do sorting and select distinct in mogodb php query

i have a mongo php query with aggregate frame work, now i want to add sorting and select distinct criteria to that query, please not that my query is working perfectly without these two criterias,
take a look
$result = $collection->aggregate(array(
array(
'$match' => array(
'Details.Model' =>"AUDI",
'Details.Color' => "RED",
"Category" =>"Car"
)
),
array(
'$unwind' => '$Details'
),
array(
'$match' => array(
'Details.Model' =>"AUDI",
'Details.Color' => "RED",
"Category" =>"Car"
)
),
array(
'$project' => array(
'Pvalue' => '$Details.Price',
"Ovalue" =>'$Details.OwnerNameFirst',
"Cvalue"=>''$Category"
),
)
));
what i want is to sort Details.Price in descending order, also Catagory and Details.OwnerNameFirst as Select Distinct
Please help
this is the result, value of $result
[{"_id":{"$id":"537dbca305a7d12f06000001"},"Pvalue":"60000","Ovalue":"jason","Cvalue":"Car"},{"_id": {"$id":"537dbca305a7d12f06000001"},"Pvalue":"59000","Ovalue":"george","Cvalue":"Jeep"},{"_id":{"$id":"537dbca305a7d12f06000001"},"Pvalue":"61000","Ovalue":"rahul""Cvalue":"Car"}]
Seems mostly there, but the question is that if we are "grouping" ( which means distinct ) then that implies there are more than one value here for "price".
So which do you want? $min $max $first $last or $avg ?
I'll use $avg as the example, but replace according to your needs:
$result = $collection->aggregate(array(
array(
'$match' => array(
'Details.Model' =>"AUDI",
'Details.Color' => "RED",
"Category" =>"Car"
)
),
array(
'$unwind' => '$Details'
),
array(
'$match' => array(
'Details.Model' =>"AUDI",
'Details.Color' => "RED",
"Category" =>"Car"
)
),
array(
'$group' => array(
'_id' => array(
"Ovalue" =>'$Details.OwnerNameFirst',
"Cvalue"=>''$Category"
),
'Pvalue' => array(
'$avg' => '$Details.Price'
)
)
),
array(
'$sort' => array(
'Pvalue' => -1,
)
)
));
So once you have a value by the distinct keys then you just add a $sort stage. But pick which of the group operators you actually want.
Check the docs for $sort:
$sort: {
Details.Price: -1
}
PHP equivalent:
array(
'$sort' => array("$Details.Price" => -1),
)
Check the PHP docs for more info.

Lithium framework multiple 'or' statements in a query (using mongoDB)

I have started work with lithium framework + mongoDB recently. I want to do a really simple query which contains multiple or statements.
I have articles in the DB with publish_up and publish_down fields. I want to fetch only those records/documents which pulbis_down field is highert than now OR null AND publish_up field lower than now OR null.
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
'$or' => array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
),
)
));
Of course this snippet is wrong hence the second or statement overwrites the first one (because the same array key).
I tried to wrap them into an individual array but gives error.
Any idea?
This query will fetch articles with (publish_down > now OR publish_down = null) AND (publish_up < now OR publish_up = null)
$items = Articles::find('all', array(
'conditions' => array(
'$or' => array(
array('publish_down' => array('$gt' => $mongoDateNow)),
array('publish_down' => null)
),
'$or' => array(
array('publish_up' => array('$lt' => $mongoDateNow)),
array('publish_up' => null)
),
)
));
I don't know about lithium but in PHP you can use multiple $OR as below
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
)
),
)
));
I think the correct answer is:
'$and' => array(
array(
'$or'=>array(
array('publish_up' => null),
array('publish_up' => array('$lt' => $mongoDateNow))
)
),
array(
'$or'=>array(
array('publish_down' => null),
array('publish_down' => array('$gt' => $mongoDateNow))
)
)
)

Categories