Laravel 5 execute aggregation with mongodb on where clause - php

Laravel 5 Eloquent sum of multiplied columns for mongo DB
This was my previous question and it got solved with the help of #Alex, now i need to add a where clause of $field != '0'
Here I am stuck I tried with the match but still I have no option left to get help from here.
Thanks

Using the aggregation pipeline where the $ne comparison query operator is in the $match pipeline:
DB::connection($this->MongoSchemaName)
->collection($this->InvoicesTable)
->raw(function($collection) use ($customer){
return $collection->aggregate([
['$match' => [
'ContactID' => (int)$customer->ContactID,
'Type' => 'PAYMENT',
'AmountDue' => [ '$ne' => 0 ]
]
],
['$group' => [
'_id' => '$ContactID',
'TotalInBaseCurrency' => [
'$sum' => ['$multiply' => ['$Total', '$CurrencyRate']]
]
]
]
]);
})

Related

How to combine fulltext search with other optinals matches in MongoDb?

I try to query my collection with only one query and 3 potentials search method:
fulltext search
classic search
search regex
This 3 matches can be executed at the same time or just one of them.
The fulltext search is the first stage pipeline as we know. Does this fulltext search can be optional in my aggregate? Because if my default value of search is "", my query returns any data. And I need data to perform my other optionals matches.
Here is my Laravel 8 controller :
Product::raw(function ($collection) use($filters, $fullText, $likeKey, $likeValue){
return $collection->aggregate([
[
'$match' =>
[
'$text' =>['$search' => $fullText],
],
],
[
'$match' => $filters
],
[
'$match' =>
[
$likeKey =>
[
'$regex' => $likeValue,
'$options' => "i"
]
]
],
[
'$addFields' =>
[
'avgReviews' => ['$avg' => '$reviews.ranking'],
'price' => ['$min' => '$variants.price'],
'equipmentsList' => [
'$reduce' => [
'input' => '$equipments.list.list',
'initialValue' => [],
'in' =>
[
'$concatArrays' => [
'$$value',
'$$this'
]
]
]
]
],
]
]);
})
->when($operations, function($products) use ($operations){
foreach($operations as $key => $operation){
return $products
->where($operation[0],$operation[1],$operation[2]);
}
})
->forPage($page,$limit)
->sortBy($sortBy, SORT_REGULAR, $order == 'desc')
->values();
$filters is an array and works fine when it's the only one match. But if I want to use $filters without $text, it returns any data. And with the third match, nothing works. Can somebody help me with this?

Correct syntax for "must not" search rule on Laravel Scout Elasticsearch "babenkoivan/scout-elasticsearch-driver" package

I am trying to add a must_not clause to my search using Laravel Scout and babenkoivan/scout-elasticsearch-driver on top of Elasticsearch.
The idea is to exclude all results where the sold field either has a timestamp of more than 14 days, or is greater than zero.
I can't seem to get the correct syntax however, and there is no documentation on how to do this on the package repo. I tried formatting it like it is in the Elasticsearch docs but this is not correct.
Here is the set of rules:
public function buildQueryPayload()
{
$query = $this->builder->query;
return [
'must' => [
'query_string' => [
'query' => $query,
],
],
'must_not' => [
'term' => [
'visible' => 0
],
'range' => [
'sold' => [
'lte' => time() - 1209601, // 14 days ago plus 1 second
'gte' => 0
]
]
],
'should' => [
...
],
];
}
Currently I get a Elasticsearch\Common\Exceptions\BadRequest400Exception error.
Here is the error complaining about the syntax:
{
"error":{
"root_cause":[
{
"type":"parsing_exception",
"reason":"[term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
"line":1,
"col":97
}
],
"type":"parsing_exception",
"reason":"[term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
"line":1,
"col":97
},
"status":400
}
Any ideas so we can get this documented for posterity? Thanks!
Try replacing 'term' with 'match'.

select sum column by with Mongodb and Laravel

I have MongoDB document which contains following data(xxx)
{
"_id" : "48e5f6b1-026f-48b8-98cb-6572cfa0eaa6",
"esti_delivery_time" : "2015-1-1",
"original_price" : NumberInt(4060),
"price":109.2,
"code" : "JS1709137",
"updated_at" : ISODate("2017-09-13T06:01:18.000+0000"),
"created_at" : ISODate("2017-09-13T03:45:54.000+0000")
}
I want to
SELECT "xxx" with SUM "price" and SUM "original_price"
Because you need the sums of the price and original_price elements, it is means that you need to group the documents by some data (one or more elements). For this task you need to use the $group aggregator.
MongoDB PHP Driver documentation
Example:
$con = new MongoDB\Client('mongodb://localhost:27017', [], [
'typeMap' => [
'root' => 'array',
'document' => 'array',
'array' => 'array'
]
]);
$collection = $con->selectDatabase("db_name")->selectCollection("collection_name");
$cursor = $collection->aggregate([
[
'$group' => [
"_id" => '$code',
"sum_price" => ['$sum' => '$price'],
"sum_original_price" => ['$sum' => '$original_price']
]
]
]);
My answer:
enter image description here
Thanks for your reply

laravel eloquent count with a groupby

If I'd have the following table structure
ID name type
1 John Admin
2 Johan Admin
3 Sam User
4 Rick User
How would I use Laravels Eloquent with a groupBy query, but still grab each record, and also sum up per type how many records each type has?
Example result would be as follow
[
'type' => 'Admin',
'records' => 2
'data' => [
0 => [
'name' => 'John'
],
1 => [
'name' => 'Johan'
]
]
],
[
'type' => 'User',
'records' => 2
'data' => [
0 => [
'name' => 'Sam'
],
1 => [
'name' => 'Rick'
]
]
]
Since you are querying all the users you should be doing the grouping after the query instead of grouping in query like:
$users = User::all()->groupBy('type');
Then you can do:
foreach ($allUsers as $type => $users) {
$type; // 'Admin'
$users->count(); // Record Count
foreach ($users as $user) {
$user->name; //
}
}
If you want the data EXACTLY like your example then it would be:
User::all()
->groupBy('type')
->map(function($users, $type) {
return [
'type' => $type,
'records' => $users->count(),
'data' => $users->pluck('name')
];
})
->values();
I think the best way to achieve this is to have a table with types related through hasMany() to your data.
Then you can use standard Eloquent tools without restructuring the data manually:
$data = Type::with('users')->withCount('users')->get();
Also, you can use DB::select('select * from xxx group by yyy') to execute the query.

Find MongoDB data with PHP

Mongodb search with PHP code:
$cond=array();
$cond=array_merge($cond,array("clicks" => array('$gt' =>6)));
if (isset($lang)){
$cond=array_merge($cond,array("$or" => array(array("lang" =>'de'),array("lang" =>'fr'))));
}
if (isset($country)){
$cond=array_merge($cond,array("$or" => array(array("country" =>'us'),array("country" =>'uk'))));
}
Problem: On the last line, the second $or of country is replacing the first $or of lang. Would be great if anyone can suggest how can we avoid this overriding issue?
Actually I'm new to MongoDB, I want to create a find query in MongoDB. I have to build the query on the basis of some condition flags (e.g. if '$country=true' only then embed country filter) for each column. Similar to SQL The output I need is:
"Where clicks > 6 and (lang = 'de' or lang = 'fr') and (country = 'us' or country = 'uk')"
This is how your resulting array should look like:
$cond = [
'$and' => [
['clicks' => [ '$gt' => 6 ]],
['$or' => [
[ 'lang' => 'de' ],
[ 'lang' => 'fr' ]
]],
['$or' => [
[ 'country' => 'us' ],
[ 'lang' => 'uk' ]
]]
]
];
Now, to achieve this by using the modular approach you have specified, you could do something like this:
$cond = [
'$and' => [
['clicks' => [ '$gt' => 6 ]]
]
];
if (isset($lang)) {
$cond['$and'][] = ['$or' => [['lang' =>'de'], ['lang' =>'fr']]];
}
if (isset($country)) {
$cond['$and'][] = ['$or' => [['country' =>'us'], ['country' =>'uk']]];
}
Hopefully this will demonstrate the way to assemble nested or/and query in PHP, so you can adjust it further as your design will demand.

Categories