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.
Related
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?
Stored a new index by the following code.
$data = array(
array("Name"=>"Norman","Email"=>"in.dolor#vulputatemauris.ca","Created"=>"2019-12-29 10:28:03","Modified"=>"2020-11-07 01:45:23"),
array("Name"=>"Drake","Email"=>"posuere#sedorcilobortis.co.uk","Created"=>"2020-11-08 14:37:00","Modified"=>"2019-08-10 06:42:07"),
array("Name"=>"Wynne","Email"=>"ligula.Donec#adipiscingenim.net","Created"=>"2019-05-19 23:30:42","Modified"=>"2019-06-09 08:13:58"),
array("Name"=>"Kirsten","Email"=>"lobortis#Suspendisseeleifend.net","Created"=>"2020-01-09 23:34:19","Modified"=>"2020-04-16 10:23:07"),
array("Name"=>"Ainsley","Email"=>"elit.dictum.eu#Quisquelibero.org","Created"=>"2019-01-22 18:14:39","Modified"=>"2019-09-02 18:44:30"),
array("Name"=>"Walker","Email"=>"ullamcorper#luctussitamet.org","Created"=>"2020-11-05 23:04:46","Modified"=>"2020-01-03 09:29:36"),
array("Name"=>"Evelyn","Email"=>"amet.metus.Aliquam#dui.org","Created"=>"2020-06-28 13:23:09","Modified"=>"2019-04-02 05:41:33"),
array("Name"=>"James","Email"=>"amet.risus#nullaCras.net","Created"=>"2020-04-20 10:15:54","Modified"=>"2020-07-22 12:04:49"),
array("Name"=>"Melvin","Email"=>"nec.eleifend.non#elit.edu","Created"=>"2020-03-07 05:19:53","Modified"=>"2018-12-30 19:33:29"),
);
$hosts = ['http://localhost:9200'];
$client = ClientBuilder::create()->setHosts($hosts)->build();
$params = [
'index' => 'dummy_data',
'id' => 'my_id',
'body' => ['data' => $data]
];
$response = $client->index($params);
Trying to search the first record by the following:
$params = [
'index' => 'dummy_data',
'body' => [
'query' => [
'bool' => [
'must' => [
[ 'match' => [ 'data.Name' => 'Norman' ] ],
],
]
]
]
];
$results = $client->search($params);
The issue is it's returning all the records where the query is matching with only the first one.
Please help with this.
Im guessing you are using the official Elasticsearch-PHP library. In that case it looks like you are indexing all provided data as exactly 1 document with the id being 'my_id'. That is why you get the the entire dataset back when your search matches.
If you want to index multiple documents at the same time, you should look at the bulk_index endpoint.
Here is the official example for reference:
for($i = 0; $i < 100; $i++) {
$params['body'][] = [
'index' => [
'_index' => 'my_index',
]
];
$params['body'][] = [
'my_field' => 'my_value',
'second_field' => 'some more values'
];
}
$responses = $client->bulk($params);
In my MongoDB database one name field is available, in this name field data is stored in the format Aaa, Bbb, Ccc, Ddd. The first letter of the word is uppercase and remaining letter is lowercase. When I apply MongoDB sort query on this data. The sorting is not working properly
My code is like below one:-
$manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$pipeline = [
[ '$match' => ['listingStatus' => 'Active'] ],
[ '$sort' => ['listingParticipants.firstName' => -1]],
[ '$group' => ['_id' => '$listingParticipants.email'] ],
[ '$limit' => 10],
[ '$skip' => 0],
];
$aggregate = new \MongoDB\Driver\Command([
'aggregate' => 'test_collection',
'pipeline' => $pipeline,
'cursor' => new stdClass
]);
$cursor = $manager->executeCommand('test_database', $aggregate);
I seen multiple solution on google, they use duplicate field with lower case and apply filter on that newly created field.
But in my project I don't create new field so please help me to solve this issue.
I want to sort data by more similar in elasticsearch with fuzzy mode
we have to record
1.panadol
2.penadol
when I search with panadol or penadol the first result is (penadol) but I want wen I type (panadol) the first result appear (panadol) and the second result id (penadol) etc ..
$params = [
'index' => 'my_index',
'type' => 'my_type',
'body' => [
"track_scores"=> true,
'sort'=>[
'name'=> ['reverse'=>true],
'_score'=> ['order'=>'desc'],
],
'query' => [
'fuzzy' => [
'name' => [
"value"=> 'panadol',
"fuzziness" => 2,
]
]
],
]
];
Fuzziness is not meant for scoring. You can find more info about it in the docs.
If you want to sort the results by relevance to the original phrase your searched for you can use either the phrase-suggester or the completion-suggester, depending on your needs (and your data).
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']]
]
]
]
]);
})