Conditional sum in MongoDB - php

here is the Mysql Query:
SELECT name, sum(case when reason = 'fb' then score else 0 end) as fb, sum(case when reason = 'email' then score else 0 end) as email from multi_group group by name
I am trying to convert this query in MongoDb:
$query = Model::raw(function($collection) {
return $collection->aggregate([
[
'$group' => [
'_id' => [
'name'=>'$name',
'fb'=> [
'$cond'=> [
[ '$eq'=> ['$reason', 'fb']],
'$score',
0
]
],
]
],
]]);
});
any help would be highly appreciable.

It is not tested though but I believe this should be ok.
$query = Model::raw(function($collection) {
return $collection->aggregate([
[
'$group' => [
'_id' => [
'name'=>'$name',
]
'fb' => ['$sum' =>
[
'$cond'=> [
[ '$eq'=> ['$reason', "fb"]],
'$score',
0
]
]
],
'email'=> [ '$sum' =>
[
'$cond'=> [
[ '$eq'=> ['$reason', "email"]],
'$score',
0
]
]
]
]
],
]);
});

i just changed 0 to 1 and it worked
$query = Model::raw(function($collection) {
return $collection->aggregate([
[
'$group' => [
'_id' => [
'name'=>'$name',
]
'fb' => ['$sum' =>
[
'$cond'=> [
[ '$eq'=> ['$reason', "fb"]],
'$score',
1
]
]
],
'email'=> [ '$sum' =>
[
'$cond'=> [
[ '$eq'=> ['$reason', "email"]],
'$score',
1
]
]
]
]
],
]);
});

Related

How to filter mongodb field from linked collection

I want to know how can I propery filter field from another collection that is linked from main collection.
Here is my filter values
if(!empty($filterDataBuyer['price'])){
$findArray['price'] = intval($filterDataBuyer['price']);
}
if(!empty($filterDataBuyer['search'])){
$findArray['full_name'] = $filterDataBuyer['search'];
}
}
$findArray['type'] = 'buyer';
The price and type works fine but the full_name does not work
And here is for getting the data
$getData = [
[
'$match' => $findArray
],
[
'$project' => [
'_id' => ['$toString' => '$_id'],
'type' => '$type',
'created_date' => '$created_date',
'offer_id' => '$offer_id',
'buyer_id' => '$buyer_id',
'traveler_id' => '$raveler_id',
'order_id' => '$order_id',
'price' => '$price'
]
],
[
'$lookup' => [
'from' => 'users',
'let' => [
'admin_id' => ['$toObjectId' => '$buyer_id'],
],
'pipeline' => [
[
'$match' => [
'$expr' => [
'$eq' => [
'$_id',
'$$admin_id'
]
],
],
],
[
'$project' => [
'_id' => ['$toString' => '$_id'],
'profile_image' => '$profile_image',
'full_name' => '$full_name'
]
],
],
'as' => 'profileData'
]
],
What I want to do is if full_name field is available, it could also filter the result by it, price and type can filter successfully but full_name is not. Result returns only if full_name has value on it.
My PHP version is 7.4.27 and mongodb extension is 1.12.0
This is just two collections, payment_details and users where payment_details has buyer_id field that is reference to users id field
From mongocompass:
payment_details:
users:
Full Code update:
if(!empty($filterDataBuyer['price'])){
/* FLIGHT-31 fix */
$findArray['price'] = intval($filterDataBuyer['price']);
}
if(!empty($filterDataBuyer['search'])){
$findArray['full_name'] = $filterDataBuyer['search'];
}
$findArray['type'] = 'buyer';
$buyer_trasections = $db->payment_details->find($findArray);
$buyerRes_trasections = iterator_to_array($buyer_trasections);
$getData = [
[
'$match' => $findArray
],
[
'$project' => [
'_id' => ['$toString' => '$_id'],
'type' => '$type',
'created_date' => '$created_date',
'offer_id' => '$offer_id',
'buyer_id' => '$buyer_id',
'traveler_id' => '$raveler_id',
'order_id' => '$order_id',
'price' => '$price'
]
],
[
'$lookup' => [
'from' => 'users',
'let' => [
'admin_id' => ['$toObjectId' => '$buyer_id'],
],
'pipeline' => [
[
'$match' => [
'$expr' => [
'$eq' => [
'$_id',
'$$admin_id'
]
],
],
],
[
'$project' => [
'_id' => ['$toString' => '$_id'],
'profile_image' => '$profile_image',
'full_name' => '$full_name'
]
],
],
'as' => 'profileData'
]
],
[
'$skip' => $page
],
[
'$limit' => $config['per_page'],
],
[
'$sort' => [ 'created_date'=> -1]
]
];
$buyer_trasec = $db->payment_details->aggregate($getData);
$buyerRes_trasec = iterator_to_array($buyer_trasec);
echo "<pre>";print_r($buyerRes_trasec);exit;
And this is the sample, first result for echo "<pre>";print_r($buyerRes_trasec);exit;

Elasticsearch query with multiple attributs and values

I try to construct, in php, an query with different attribut:
this following code work :
$searchParams = [
'body' => [
"from"=> 0,
"size"=> 30000,
'query' => [
'filtered'=> [
'filter' => [
'bool' => [
'must' => [
'terms' => [
'field_support' => [105,106,1896,1897]
]
]
]
]
]
]
]
];
But when i add "term" it's not working:
$searchParams = [
'body' => [
"from"=> 0,
"size"=> 30000,
'query' => [
'filtered'=> [
'filter' => [
'bool' => [
'must' => [
'terms' => [
'field_support' => [105,106,1896,1897]
],
'term' => [
'title' => ["le jeu de la dame"]
]
]
]
]
]
]
]
];
I don't understand why it's doesn't works.
Can somebody help me ? Thanks
You need to surround your terms and term query with another associative array, like this:
$searchParams = [
'body' => [
"from"=> 0,
"size"=> 30000,
'query' => [
'filtered'=> [
'filter' => [
'bool' => [
'must' => [
[
'terms' => [
'field_support' => [105,106,1896,1897]
]
],
[
'term' => [
'title' => ["le jeu de la dame"]
]
]
]
]
]
]
]
]
];
UPDATE
Variant with match
$searchParams = [
'body' => [
"from"=> 0,
"size"=> 30000,
'query' => [
'filtered'=> [
'query' => [
'match' => [
'title' => ["le jeu de la dame"]
]
],
'filter' => [
'terms' => [
'field_support' => [105,106,1896,1897]
]
]
]
]
]
];

Elastic Search PHP Client Date Range Query

I have this code what executes an query.
I am using the official php elastic search library.
https://github.com/elastic/elasticsearch-php
The field "Tijdsperiode" is in this format : ( 2016-01-30 00:00:00 ) ( YY-MM-DD HH:MM:SS )
$params = [
'index' => 'veenendaal2',
'type' => 'passanten2',
'body' => [
'query' => [
'match_all' => [],
'filter' => [
'range' => [
'Tijdsperiode' => [
'gte' => '2016-01-30 01:00:00',
'lte' => '2016-01-30 08:00:00'
]
]
]
],
],
];
$response = $client->search($params);
var_dump($response);
I just wonder what the format need to be to get results between the 2 dates.
When i do this :
$params = [
'index' => 'veenendaal2',
'type' => 'passanten2',
'body' => [
'query' => [
'match_all' => [],
],
],
];
It's working fine but i need the results between the 2 dates!
I also tried this but with no result :
$json = '{
"query": {
"bool": {
"must": [
{
"range": {
"Tijdsperiode": {
"gt": "2016-01-30 07:00:00",
"lt": "2016-01-30 09:00:00"
}
}
}
]
}
}
}';
$client = ckan_graphmapper_client();
$params = [
'index' => 'veenendaal2',
'type' => 'passanten2',
'body' => $json
];
$response = $client->search($params);
I also tried it with a mapping :
$params = [
'index' => 'veenendaal2',
'type' => 'passanten2',
'size' => $size,
'body' => [
'query' => [
"match_all" => [],
'filter' => [
'range' => [
'Tijdsperiode' => [
'gte' => '2016-01-30 01:00:00',
'lte' => '2016-01-30 08:00:00'
]
]
]
],
'mappings' => [
'_default_' => [
'properties' => [
'Tijdsperiode' => [
'type' => 'date',
'format' => 'yyyy-MM-dd HH:mm:ss'
]
]
]
]
]
];
How to do the right syntax for choosing between 2 dates?. Both string formats ( 2016-01-30 00:00:00 ) ( YY-MM-DD HH:MM:SS )
Thanks!
So it turns out my import of data was not mapping the correct way.
The date field was recognised as a string value.
When i finnaly had the correct mapping in elastic i could do this query :
$query = [
'query' => [
'filtered' => [
'query' => [
'match_all' => []
],
'filter' => [
'range' => [
'Tijdsperiode' => [
'gte' => $start,
'lte' => $end
]
]
]
]
]
];

mongo1:27017: exception: aggregation result exceeds maximum document size (16MB)

I'm trying to run a mongo query in my laravel app but receiving the error listed in the title of this post. I think I need to set useCursor to true but am having trouble getting it to work. Here's my code:
$email_duplicates = User::raw(function ($collection) {
return $collection->aggregate(
[
[
'$group' => [
'_id' => [
'email' => '$email',
],
'uniqueIds' => [
'$addToSet' => '$_id',
],
'count' => [
'$sum' => 1,
],
],
],
[
'$match' => [
'count' => [
'$gt' => 1,
],
],
],
],
[
'allowDiskUse' => true,
],
[
'useCursor' => true,
]
);
});
anyone know what I'm doing wrong?
Thanks!

Invalid Input Resource Mongodb Command PHP

I am trying to get around the 30 second cursor time limit and avoid a MongoCursorTimeoutException by using DB->command method as seen here: MongoCursorTimeoutException for aggregate function
When I try to aggregate, command instantly returns:
array(3) { ["ok"]=> float(0) ["errmsg"]=> string(42) "Invalid input resource, " ["code"]=> int(17138) } There is pretty much no documentation on this and the only think I could find is the source code where the error takes place https://github.com/mongodb/mongo/blob/master/src/mongo/db/pipeline/pipeline.cpp#L327
Can someone please help? The pipeline works fine if I run collection->aggregate(pipeline, options) so I don't think it is the pipeline. My code is below:
$connection = new MongoClient( 'mongodb://user:pass#mydb.biz' );
$summaryDB = $connection->selectDB('Summary');
$summaryCollection = $summaryDB->selectCollection('hitSummary');
//agg pipeline
$pipeline =
[
[
'$match' => [
'date' => [
'$gte' => $weekAgo,
'$lt' => $today,
]
]
], [
'$group' => [
'_id' => [
'client' => '$client',
'date' => '$date',
],
//conversions
'z1is' => [ '$sum' => '$actions.sales.import.z1.count' ],
'z2is' => [ '$sum' => '$actions.sales.import.z2.count' ],
'z3is' => [ '$sum' => '$actions.sales.import.z3.count' ],
'z1ps' => [ '$sum' => '$actions.sales.pixel.z1.count' ],
'z2ps' => [ '$sum' => '$actions.sales.pixel.z2.count' ],
'z3ps' => [ '$sum' => '$actions.sales.pixel.z3.count' ],
'z1as' => [ '$sum' => '$actions.sales.apiOnly.z1.count' ],
'z2as' => [ '$sum' => '$actions.sales.apiOnly.z2.count' ],
'z3as' => [ '$sum' => '$actions.sales.apiOnly.z3.count' ],
'z1ss' => [ '$sum' => '$actions.sales.s2s.z1.count' ],
'z2ss' => [ '$sum' => '$actions.sales.s2s.z2.count' ],
'z3ss' => [ '$sum' => '$actions.sales.s2s.z3.count' ],
//clicks
'z1ic' => [ '$sum' => '$actions.click.import.z1.count' ],
'z2ic' => [ '$sum' => '$actions.click.import.z2.count' ],
'z3ic' => [ '$sum' => '$actions.click.import.z3.count' ],
'z1pc' => [ '$sum' => '$actions.click.pixel.z1.count' ],
'z2pc' => [ '$sum' => '$actions.click.pixel.z2.count' ],
'z3pc' => [ '$sum' => '$actions.click.pixel.z3.count' ],
'z1ac' => [ '$sum' => '$actions.click.apiOnly.z1.count' ],
'z2ac' => [ '$sum' => '$actions.click.apiOnly.z2.count' ],
'z3ac' => [ '$sum' => '$actions.click.apiOnly.z3.count' ],
'z1sc' => [ '$sum' => '$actions.click.s2s.z1.count' ],
'z2sc' => [ '$sum' => '$actions.click.s2s.z2.count' ],
'z3sc' => [ '$sum' => '$actions.click.s2s.z3.count' ],
//impressions
'z1ii' => [ '$sum' => '$actions.display.import.z1.count' ],
'z2ii' => [ '$sum' => '$actions.display.import.z2.count' ],
'z3ii' => [ '$sum' => '$actions.display.import.z3.count' ],
'z1pi' => [ '$sum' => '$actions.display.pixel.z1.count' ],
'z2pi' => [ '$sum' => '$actions.display.pixel.z2.count' ],
'z3pi' => [ '$sum' => '$actions.display.pixel.z3.count' ],
'z1ai' => [ '$sum' => '$actions.display.apiOnly.z1.count' ],
'z2ai' => [ '$sum' => '$actions.display.apiOnly.z2.count' ],
'z3ai' => [ '$sum' => '$actions.display.apiOnly.z3.count' ],
'z1si' => [ '$sum' => '$actions.display.s2s.z1.count' ],
'z2si' => [ '$sum' => '$actions.display.s2s.z2.count' ],
'z3si' => [ '$sum' => '$actions.display.s2s.z3.count' ],
]
], [
'$project' => [
'impressions' => [ '$add' => ['$z1ii', '$z2ii', '$z3ii',
'$z1pi', '$z2pi', '$z3pi',
'$z1ai', '$z2ai', '$z3ai',
'$z1si', '$z2si', '$z3si'] ],
'clicks' => [ '$add' => ['$z1ic', '$z2ic', '$z3ic',
'$z1pc', '$z2pc', '$z3pc',
'$z1ac', '$z2ac', '$z3ac',
'$z1sc', '$z2sc', '$z3sc'] ],
'importSales' => [ '$add' => ['$z1is', '$z2is', '$z3is'] ],
'pixelSales' => [ '$add' => ['$z1ps', '$z2ps', '$z3ps'] ],
'apiSales' => [ '$add' => ['$z1as', '$z2as', '$z3as'] ],
's2sSales' => [ '$add' => ['$z1ss', '$z2ss', '$z3ss'] ],
]
]
];
//do something with this
$options = [ 'timeout' => -1 ];
$result = $summaryDB->command(
[
'aggregate' => $summaryCollection,
'pipeline' => $pipeline,
],
$options
);
var_dump($result);
When you run DB command, the first argument is the name of the command as the key and the value is the name of the collection.
In your case you should be passing "hitSummary" as the value of 'aggregate' and not the collection object.
See simple command example here: http://php.net/manual/en/mongodb.command.php

Categories