How to use geoNear with the current PHP MongoDB Driver? - php

I'm currently working with the current PHP MongoDB\Driver .
I need to use an geoNear query to fetch points from my current location. The required 2dsphere index is already set, the query works in the console and delivers multiple results:
db.runCommand({geoNear: 'pois', near: [ 52.264633, 6.12485 ], spherical: true, maxDistance: 1000, distanceField: 'distance'})
Since the previous methods are deprecated, I can't use the old aggregate functions.
I'm now trying to find the right way to build the query I need with the current Query or Command classes.
What I've tried is the following:
$query = array(
'geoNear' => 'pois',
"near" => array(
52.264633,
6.12485
),
"spherical" => true,
"maxDistance" => 1000,
"distanceField" => "distance"
);
$cmd = new MongoDB\Driver\Command($query);
$returnCursor = $this->conn->executeCommand("database.pois", $cmd);
$arrReturn = $returnCursor->toArray();
return $arrReturn;
If I use this, I will return this Runtime Error:
"exception": [
{
"type": "MongoDB\\Driver\\Exception\\RuntimeException",
"code": 18,
"message": "Failed to decode document from the server."
}
]"
I couldn't find a solution for my case and also I couldn't find more information to this error.
If I change the Command up to a Query, the execution doesn't fail, but there are no results.
My mongodb is on the version 3.2, my PHP version is PHP Version 7.0.16-4+deb.sury.org~trusty+1 and the mongodb Exension is version 1.2.3

You can use the aggregate in the following way with new driver.
$pipeline = array(array(
'$geoNear'=> array(
'near' => array(
52.264633,
6.12485
),
'spherical' => true,
'maxDistance' => 1000,
'distanceField' => "distance"
)));
$cmd = new \MongoDB\Driver\Command([
'aggregate' => 'pois',
'pipeline' => $pipeline
]);
$returnCursor = $this->conn->executeCommand("database", $cmd);
$arrReturn = $returnCursor->toArray();

There is also a Library from Mongo that expands the default functionality of the driver to make it a little more user friendly
but as its not built into the php website its easy to miss
MongoDB\Collection::aggregate($pipeline, $options)
where
$pipeline = array(array(
'$geoNear'=> array(
'near' => array(
52.264633,
6.12485
),
'spherical' => true,
'maxDistance' => 1000,
'distanceField' => "distance"
)
));

Related

Using like operator in Elasticserch PHP

I'm using elasticsearch version 8.4 with PHP. I created the index articles e and he has all the registers that are present in the correspondent table in database.
I need to do a search with elasticsearch that return the same results that a SQL search would do.
SELECT *
FROM articles
WHERE title LIKE '%Document%'
However, the results are not the same using elasticsearch php. The php code follows:
<?php
require_once "vendor/autoload.php";
use Elastic\Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->setBasicAuthentication('elastic','secret')
->build();
$params = [
'index' => 'articles',
'from' => 0,
'size' => 5000,
'body' => [
'query' => [
'match' => [
'title' => 'Document'
]
]
]
];
if (!empty($results['hits']['hits']))
{
echo "<pre>";
print_r($results['hits']['hits']);
echo "</pre>";
}
I tried 'wildcards' and 'regexp' instead of 'match', but it not worked.
I read these pages of docs to help in this case:
https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-like-rlike-operators.html#sql-like-operator https://www.elastic.co/guide/en/elasticsearch/client/php-api/8.4/search_operations.html
Is there any to reproduce this elasticsearch php code return same results of sql query executed directly in database?

Get error 'MongoResultException' when use aggregate in mongoDB

When i use aggregatein PHP, i get error:
MongoResultException: localhost:27017: The 'cursor' option is
required, except for aggregate with the explain argument
I use mongoDB 3.6 and PHP 5.6
Please see the photo
My Code:
$dbconn = new MongoClient();
$c = $dbconn->selectDB("test")->selectCollection("users");
$ops = array(
array(
'$lookup' => array(
'from' => 'news',
'localField' => '_id',
'foreignField' => 'user_id',
'as' => 'user_docs'
)
)
);
$results = $c->aggregate($ops);
var_dump($results);
For other people who may run into the same problem, here is the solution.
The aggregator command was modified in version 3.6, as indicated in the documentation:
Changed in version 3.4: MongoDB 3.6 removes the use of aggregate command without the cursor option unless the command includes the explain option. Unless you include the explain option, you must specify the cursor option.
In Mongo, you could just add the cursor option without specifying any parameter, as specified in the documentation:
cursor: {}
In PHP, you would need to specify the option like this, new stdClass()corresponding to an empty object '{}' in Mongo :
$results = $c->aggregate($ops, ['cursor' => new \stdClass()]);
Here's how to do it for your example :
$dbconn = new MongoClient();
$c = $dbconn->selectDB("test")->selectCollection("users");
$ops = array(
array(
'$lookup' => array(
'from' => 'news',
'localField' => '_id',
'foreignField' => 'user_id',
'as' => 'user_docs'
)
)
);
$results = $c->aggregate($ops, ['cursor' => new \stdClass()]);
var_dump($results);
If you want to take advantage of calling 'cursor' to add parameters, such as batchSize, you can do it like this :
$results = $c->aggregate($ops, ['cursor' => ['batchSize' => 200]]);
All the parameters are listed in the documentation page linked above.

How to write MongoDB query in core PHP?

I have created query in mongoDB. In MongoChef this query produces more than 10 thousand records in less than 2 seconds. Now I want to execute this query in PHP.
So i don't know how to write query in php as I read various documents on internet but confused how to implement it.
db.PMS.aggregate(
[
{$project:
{EventTS:1,MainsPower:1,PanelID:1}
},
{$unwind:
{path:"$MainsPower",includeArrayIndex:"arrayIndex",preserveNullAndEmptyArrays:true}
},
{ $match: { "MainsPower":{$ne:null}}},
{ $match: { "EventTS":{$gt:new Date("2016-01-01")}}},
{$project:
{MainsPower:1,
PanelID:1,
timestamp:{"$add":
[{'$subtract' : ["$EventTS",new Date("1970-01-01")]},
{"$multiply":[60000,"$arrayIndex"]}
]}
}
}
]
);
You can use some resources available on the php official documentation. A mapping of sql queries in php to mongoDB queries in php can be found here.
Also I have a demo login and registration script at my github. You can view those in this repo.
If you use MongoDB PHP Library you should be able to do something similar to this:
$mongo = new MongoClient();
$database = $mongo->examples;
$collection = $database->PMS;
$pipeline = [
[
'$project' => [
'EventTS' => 1,
'MainsPower' => 1,
'PanelID' => 1,
]
],
[
'$unwind' => [
'path' => '$MainsPower',
'includeArrayIndex' => 'arrayIndex',
'preserveNullAndEmptyArrays' => true
]
],
...
];
$cursor = $collection->aggregate($pipeline);

Can't query with mongodb-1.1.x php driver

I just updated mongodb to version 3.2 and updated my php driver to the latest. Here is the docs.
They changed almost everything with this new driver and there is not enough documentation I think. I couldn't find how to count, limit and sort the data with php as before.
I found sort method in mongodb website, but there is nothing about it in php docs and source code.
Is there anyone who has dealt with this new driver? How can I sort and limit my query results with php?
To use the new mongo php driver, unlike the old version which just requires mongo.so or mongo.dll to be installed, you will need to get the package mongodb/mongodb through composer:
composer.phar require "mongodb/mongodb=^1.0.0#beta"
Then you can use this example for an initial try:
<?php
require 'vendor/autoload.php'; // include Composer goodies
$manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$collection = new MongoDB\Collection($manager, "db_name.collection_name");
$result = $collection->find( [ 'id' => '1', 'name' => 'John' ] );
foreach ($result as $entry)
{
echo $entry->id, ': ', $entry->name, "\n";
}
?>
More examples can be found in https://github.com/mongodb/mongo-php-library/blob/master/examples/bulkwrite.php and https://github.com/mongodb/mongo-php-library/blob/master/examples/write.php
The count method can be found in https://github.com/mongodb/mongo-php-library/blob/master/src/Collection.php
sort and limit are the options to add to find() method:
$options = [
'sort' => ['id' => 1],
'limit' => 5
];
$result = $collection->find( [ 'id' => '1', 'name' => 'John' ], $options );

MongoDB aggregation does not work (or is very slow) with PHP and works perfectly in shell?

I'm trying to use the aggregate method on my collection (containing more than 20M documents).
I first tried it in the Windows shell :
db.data.aggregate([
{$match: {firstname: "Roger"}},
{$group:{"_id":"$id_car",count:{$sum: 1}}},
{$sort: {count: -1}},
{$limit: 50}])
And it works perfectly, returning the results after a few seconds.
When I "translate" it in PHP :
$data = $db->data;
$ops = array(
array(
'$match' => array(
'firstname' => 'Roger'
)
),
array(
'$group' => array(
'_id' => '$id_car',
'count' => array(
'$sum' => 1
)
)
),
array(
'$sort' => array(
'count' => -1
)
),
array(
'$limit' => 4
)
);
$res = $data->aggregate($ops);
I get a timeout PHP Fatal error :
Uncaught exception 'MongoCursorTimeoutException' with message 'localhost:27017: cursor timed out (timeout: 30000, time left: 30:0, status: 0)'
I don't know if I've made a mistake in my PHP code, or if aggregate is supposed to be much slower in PHP than in shell ?
Also, I have added an index on "firstname" field to make the query go faster.
By the way, is there any way to set the timeout to infinity for this kind of call ?
Thanks a lot for your help !
Joe
I don't really know about your issue (PHP being slower than the MongoShell), but something I've done that allowed me to run an aggregation in PHP (due to the timeout problems) is changing the way I invoked the aggregation.
Hope this helps someone that reaches this page because of the timeout problems, like I did!
Instead of $data->aggregate($ops) I ran the following equivalent to your case:
$db->command(
array('aggregate' => 'data', 'pipeline' => $ops),
array('timeout' => 100000000)
)
Notice that you must run the command over the $db and not your collection.

Categories