I'm trying to build a query to search geospatial data in mongo using php-mongo library.
Object structure
{
"_id" : ObjectId("536ecef59bdc8977f1e9c06f"),
"location" : {
"type" : "Point",
"coordinates" : [
[
-74.220408,
40.727703
]
]
},
"bounds" : {
"type" : "Polygon",
"coordinates" : [
[
[
-74.221403,
40.728457
],
[
-74.219413,
40.728457
],
[
-74.219413,
40.726949
],
[
-74.221403,
40.726949
],
[
-74.221403,
40.728457
]
]
]
},
"tile" : {
"type" : "Polygon",
"coordinates" : [
[
[
-74.220498,
40.727772
],
[
-74.220318,
40.727772
],
[
-74.220318,
40.727634
],
[
-74.220498,
40.727634
],
[
-74.220498,
40.727772
]
]
]
},
"status" : "2",
"dev" : "0"
}
Indexes
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "atlantic.Analyzer_Marks"
},
{
"v" : 1,
"key" : {
"location.coordinates" : "2d"
},
"name" : "location.coordinates_2d",
"ns" : "atlantic.Analyzer_Marks"
},
{
"v" : 1,
"key" : {
"bounds" : "2dsphere"
},
"name" : "bounds_2dsphere",
"ns" : "atlantic.Analyzer_Marks",
"2dsphereIndexVersion" : 2
},
{
"v" : 1,
"key" : {
"tile" : "2dsphere"
},
"name" : "tile_2dsphere",
"ns" : "atlantic.Analyzer_Marks",
"2dsphereIndexVersion" : 2
}
]
$mongo = new MongoClient("mongodb://someserver.com:27017");
$marks = $mongo->selectDB('atlantic');
$q = array('bounds' => array(
'$geoWithin' => array(
'$geometry' => array(
'type' => 'Polygon',
'coordinates' => array(array(
array(40.125246,-74.327963),
array(40.125246,-74.325989),
array(40.123738,-74.325989),
array(40.123738,-74.327963),
array(40.125246,-74.327963)
))
)
)
)
);
$marks = new MongoCollection($marks,'Analyzer_Marks');
$marks = $marks->find($q);
//var_dump($marks);
$results = array();
if(!empty($marks)){
foreach($marks as $mark) {
$results[] = array(
"location" => $mark['location'],
"tile" => $mark['tile'],
"status" => $mark['status']
);
}
}
This is the error I get:
Fatal error: Uncaught exception 'MongoCursorException' with
message 'someserver.com:27017: Can't canonicalize query: BadValue bad
geo query' in /var/www/html/one-call/lib/somefile.php:97
MongoDB Version 2.6.1
I can reproduce that error. I think you are missing one more array call wrapping around the array of coordinates:
$mongo = new MongoClient("mongodb://someserver.com:27017");
$marks = $mongo->selectDB('atlantic');
$q = array('bounds' => array(
'$geoWithin' => array(
'$geometry' => array(
'type' => 'Polygon',
'coordinates' => array(
array(
array(40.125246,-74.327963),
array(40.125246,-74.325989),
array(40.123738,-74.325989),
array(40.123738,-74.327963),
array(40.125246,-74.327963)
)
)
)
)
)
);
after modifying the code I don't receive that error anymore
Related
I'm new to ElasticSearch and don't really understand how the queries works...
My indexing example
{
"_index" : "indexing001",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"_seq_no" : 242,
"_primary_term" : 2,
"found" : true,
"_source" : {
"type" : 1,
"sub_type" : null,
"user" : {
"id" : 1,
"name" : "tk6z2 gcnouvqmr"
},
"editor_user" : [ ],
"content" : [
{
"title" : "Title #3",
"short_text" : "Article #3 short text",
"full_text" : "Article #3 full text",
"locale" : "de-DE"
}
],
"flags" : [ ],
"location" : [ ],
"start_date" : 1658793600,
"end_date" : 1658793600,
"_users" : [ ]
}
}
I want to query the text to match the field content.title and content.short_text, query user by _users field.
For example my function is:
public static function search(
string $text = '',
int $user = 0
): array
{
try {
$model = new someModelClass();
$fields = [
'content.title',
'content.short_text',
];
$result = $model::find()->query( [
'bool' => [
'should' => [
'multi_match' => [
'query' => $text,
'fields' => $fields,
],
],
'filter' => [
[ 'term' => [ '_users.id' => $user ] ],
[ 'term' => [ '_users' => [] ] ],
]
],
] )->all();
return $result;
}
catch ( Exception $e ) {
throw new Exception( $e->getMessage() );
}
}
convert it to SQL it should be something like: SELECT * FROM 'indexing001' WHERE (content.title LIKE %search% OR content.short_text LIKE %search%) AND (users.id = 1 OR users = '')
How to write it in ElasticSearch query?
Thanks in advance!!
Well in that case i would recommend to use the Elasticsearch-PHP client.
Please install appropriate client using composer.
For a match query like below
curl -XGET 'localhost:9200/my_index/_search' -d '{
"query" : {
"match" : {
"testField" : "abc"
}
}
}'
You can make a query in your PHP Script like this
$params = [
'index' => 'my_index',
'body' => [
'query' => [
'match' => [
'testField' => 'abc'
]
]
]
];
$results = $client->search($params);
Check more operations here.
I'll try to reproduce your SQL and provide JSON query example, u will ez adapt it to PHP query method.
{
"query": {
"bool": {
"should": [
{"multi_match": {
"fields": ["content.title", "content.short_text"],
"query": "%query here%"
}}
],
"filter": {
"bool": {
"should": [
{"match": {"user.id": "%id here%"}},
{"match": {"user": []}},
]
}
}
}
}
}
I need to recover one array from an array... I made in mongodb shell with this sentence:
db.users.aggregate([
{$match: {'userQueries.queryId': 'gr591dd6b06149d9.07403049'}},
{$project: {
userQueries: {$filter: {
input: '$userQueries',
as: 'query',
cond: {$eq: ['$$query.queryId', 'gr591dd6b06149d9.07403049']}
}},
_id: 0
}}
])
I'm using this driver: https://secure.php.net/manual/en/set.mongodb.php
My document looks like this:
{
"_id" : ObjectId("591dd67cc4ef6009ae38e292"),
"userId" : 0,
"email" : "dmance#dmance.org",
"password" : "dmance",
"fullName" : "daniel",
"organization" : "dmance",
"userQueries" : [
{
"queryResultArray" : [
{
"docsArray" : [
{
"hgnc_id" : "HGNC:26970"
}
],
"queryResultId" : 0,
"terms" : [
"COX2",
"COX20"
]
},
{
"docsArray" : [
{
"hgnc_id" : "HGNC:130"
}
],
"queryResultId" : 1,
"terms" : [
"ACT"
]
},
{
"docsArray" : [
{
"hgnc_id" : "HGNC:7422"
}
],
"queryResultId" : 2,
"terms" : [
"COX3"
]
}
],
"queryId" : "gr591dd6b06149d9.07403049",
"queryName" : "Unnamed query"
},
{
"queryResultArray" : [
{
"docsArray" : [
{
"hgnc_id" : "HGNC:26970"
}
],
"queryResultId" : 0,
"terms" : [
"COX2",
"COX20"
]
},
{
"docsArray" : [
{
"hgnc_id" : "HGNC:130"
}
],
"queryResultId" : 2,
"terms" : [
"COX3"
]
}
],
"queryId" : "gr591de08337e901.19728995",
"queryName" : "Unnamed query"
}
]
}
I want to get only the array matching the queryId field.
As I said I made it in the mongo shield but i cant translate it into php.
It was already answered. I'm sorry. This is how I solved the problem.
$mongo = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$pipeline = [
[
'$match' =>
[
'userQueries.queryId' => 'gr591dd6b06149d9.07403049',
],
],
[
'$project' =>
[
'userQueries' => [ [
'$filter' => [
'input' => '$userQueries',
'as' => 'query',
'cond' => [
'$eq' => [
'$$query.queryId', 'gr591dd6b06149d9.07403049',
]
],
],
],
],
'_id' => 0
],
],
];
$command = new \MongoDB\Driver\Command([
'aggregate' => 'users',
'pipeline' => $pipeline
]);
$cursor = $mongo->executeCommand('genenames', $command);
When the below query is run the results are displayed in mongo shell.
Sample Records
{
"_id" : ObjectId("587e21df6e79d255011a9c6a"),
"vendor_id" : "101",
"subscription_id" : 14,
"created_at" : ISODate("2017-01-17T13:53:35.272Z")
}
{
"_id" : ObjectId("587e21df6e79d255011a9c6c"),
"vendor_id" : "102",
"subscription_id" : 14,
"created_at" : ISODate("2017-01-17T13:56:35.272Z")
}
Query
db.user_config.aggregate({$group:
{
_id : "$subscription_id",
list:
{
$push:
{
_id: "$_id",
vendor_id: "$vendor_id"
}
}
}})
Results
/* 1 */
{
"result" : [
{
"_id" : 14,
"list" : [
{
"_id" : ObjectId("587e21df6e79d255011a9c6a"),
"vendor_id" : "user_101"
},
{
"_id" : ObjectId("587e21df6e79d255011a9c6b"),
"vendor_id" : "user_101"
}
]
}
],
"ok" : 1.0000000000000000
}
But when same thing is done through laravel the following error occurs. $pipeline is not a list (unexpected index: "$group")
Below is the laravel code
$configuration_list = UserConfig::raw()->aggregate([
'$group' => [
'_id' => '$subscription_id',
'list' => ['$push' =>
['_id' => '$_id', 'vendor_id' => '$vendor_id']]
]
]
);
Can someone please help me solve this issue..
Wrap the aggregation pipeline steps in an array:
$pipeline = [
[
'$group' => [
'_id' => '$subscription_id',
'list' => [
'$push' => [
'_id' => '$_id',
'vendor_id' => '$vendor_id'
]
]
]
]
];
$configuration_list = UserConfig::raw()->aggregate($pipeline);
My aim is to create inner array to main array when search for userid as 1
Below is my data
{ "_id" : 2,
"name" : "test1",
"data" :[{"_id" : "1","file" : "nic", "userid" : [1,2 ]},
{"_id" : "2","file" : "nic1","userid" : [1 ] },
{"_id" : 3,"file" : "nick2","userid" : [1,2 ]}
]},
{ "_id" : 3,
"name" : "test2",
"data" : [{"_id" : "1","file" : "nic","userid" : [1,2 ] },
{"_id" : "2","file" : "nic1", "userid" : [3,2 ] }
]}
need to get out put as
{"_id" : 1,"file" : "nic", "userid" : [1,2 ],"main_name" : "test1","main_id" : 2},
{"_id" : 2,"file" : "nic1","userid" : [1 ] ,"main_name" : "test1","main_id" : 2 },
{"_id" : 3,"file" : "nick2","userid" : [1,2 ],"main_name" : "test2","main_id" : 3},
{"_id" : 1,"file" : "nic","userid" : [1,2 ] ,"main_name" : "test2" ,"main_id" : 3}
Basically the same answer to your last question, but without the $group to reconstruct the array and use a $project instead to restructure the document from the already de-normalized array elements.
$collection->aggregate(array(
array( '$match' => array( "data.userid" => 1 )),
array( '$unwind' => '$data' ),
array( '$match' => array( 'data.userid' => 1 )),
array(
'$project' => array(
'_id' => '$data._id',
'nic' => '$data.nic',
'user_id' => '$data.user_id',
'main_name' => '$name',
'main_id' => '$_id'
)
)
))
I'm having Mongo structure like this,
"campaigns":[{
"summary" :
[ {
"postcode" : [ {
"id" : "71",
"name" : "Recall 1",
"qty" : 3,
"history" :
[ { "timestamp" : "2014-12-16 11:15:32",
{ "timestamp": "2014-12-16 11:15:53"
} ]
} ]
},
{
"postcode" :
[ {
"id" : "72",
"name" : "Recall 2",
"qty" : 1,
"history" : [ { "timestamp" : "2014-12-16 11:15:53" } ]
} ]
}]
I'm trying to i) increment qty of postcode.id : 72 ii) insert another timestamp for that same postcode id 72.
My code:
$collection->update(array("campaigns.task.id" => $b,"_id"=> new MongoId($objectid),"campaigns.0.summary.0.postcode.0.id" => $a), array('$inc' => array('campaigns.0.summary.0.postcode.0.qty' => 1)));
$collection->update(array("campaigns.task.id" => $b,"_id"=>new MongoId($objectid),"campaigns.0.summary.0.postcode.0.id" => $a),
array('$addToSet' => array('campaigns.0.summary.0.postcode.0.history' => array("timestamp"=>$now->format('Y-m-d H:i:s')))));
but postcode.id = 72 not gets updated, i'm confused with this nested subdocument can anyone suggest me the solution ?