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')
Related
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.
$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.
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.
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.
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))
)
)
)