MongoDB - PHP Group By Count - php

I have this code :
$data=$collection1->aggregate(array( '$group'=> array('_id'=>$valoreScelto,'contatore'=>array('$sum'=>1))));
$valoreScelto is a valid field of document MongoDB, that i retry by FORM.
$valoreScelto = trim('$'.$campoSelezionato);
I obtain this error:
Fatal error: Call to a member function aggregate() on string

UPDATE:
The error says: You are trying to access the method "aggregate", in the string (Variable $collection1 have type - string).
You need to check $collection1 (for example var_dump). $collection1 must be Collection (or in mongo extension MongoCollection).
You can get a collection like this:
$yourConnectInDB = new Client(...); // or MongoClient(...);
$db = $yourConnectInDB->selectDatabase('YOUR DB NAME');
$collection1 = $db->selectCollection('YOUR COLLECTION NAME');
Also, in your code you want to use the aggregation like this:
$ops = array( // base array
array(
'$group' => array(
"_id" => $valoreScelto,
"contatore" => array('$sum'=>1),
)
),
// other pipeline
);
$data=$collection1->aggregate($ops);
Read this and this

I tried the above answer as well and it wasn't returning anything. After a lot of trying I figured out that I had missed a keyword without which the above query was not going to work. I am pasting the code below.
$ops = [
[
'$group' => [
"_id" => $valoreScelto,
"contatore" => ['$sum'=>1],
]
]
];
$data=$collection1->aggregate($ops)->toArray();

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?

Elasticsearch Unknown key for a VALUE_STRING in [scroll]

I am trying to use the PHP API, and same example as given in the code
https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/_search_operations.html#_scrolling
$client = ClientBuilder::create()->build();
$params = [
"scroll" => "30s", // how long between scroll requests. should be small!
"size" => 50, // how many results *per shard* you want back
"index" => "my_index",
"body" => [
"query" => [
"match_all" => new \stdClass()
]
]
];
// Execute the search
// The response will contain the first batch of documents
// and a scroll_id
$response = $client->search($params);
But getting error like this Unknown key for a VALUE_STRING in [scroll].
Currently using Elasticsearch version 6.2.2
Any ideas?
The problem is that you put scroll parameter in json body, but it should be instead in the URL. e.g
index-name/_search?scroll=30s
Don't forget to remove it from $params as well
You may have accidentaly put scroll attribute inside body.

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.

PHPMongo - Find and Returned only Matched embedded document in MongoDB

I am having trouble in returning matched embedded document using sokil PHPMongo ODM library. I am new to ODM concept and following is my document structure of collection Project:
{
"_id" : ObjectId("59f889e46803fa3713454b5d"),
"projectName" : "usecase-updated",
"classes" : [
{
"_id" : ObjectId("59f9d7776803faea30b895dd"),
"className" : "OLA"
},
{
"_id" : ObjectId("59f9d8ad6803fa4012b895df"),
"className" : "HELP"
},
{
"_id" : ObjectId("59f9d9086803fa4112b895de"),
"className" : "DOC"
},
{
"_id" : ObjectId("59f9d9186803fa4212b895de"),
"className" : "INVOC"
}
]
}
So in my query first criteria is to get the Project with a matched ID and 2nd criteria is to to retrieve only the class from the classes array of embedded documents with a specific id.This is how i am building the query:
$collection = $PHPMongoDBInstance->getCollection("Project");
$result = $collection->getDocument(
"59f889e46803fa3713454b5d",
function (\Sokil\Mongo\Cursor $cursor) {
// get embedded documents with matched id
$cursor->whereElemMatch("classes", $cursor->expression()->where("_id", new MongoId("59f9d7776803faea30b895dd")));
}
);
I was expecting it to return only the embedded document of OLA from the usecase-updated document like this:
{
"_id" : ObjectId("59f889e46803fa3713454b5d"),
"projectName" : "usecase-updated",
"classes" : [
{
"_id" : ObjectId("59f9d7776803faea30b895dd"),
"className" : "OLA"
}
]
}
But PHPMongo library is returning the whole Project Document (shown in the start of question) with all the classes. Someone suggested to look into aggregation framework. But problem is there is not good enough documentation on the PHPMongo for using array aggregation functions (like $filter)
I tried it by using native instance of MongoCollection and with that i can use the findOne method to project my final result using this way:
$result = $collection->getMongoCollection("Project")->
findOne(array("_id" => new MongoId("59f889e46803fa3713454b5d")),
array("classes" =>
array('$elemMatch' =>
array("_id" => new MongoId("59f9d7776803faea30b895dd")))));
If i want to achieve the similar projection using the getDocument method of sokil PHPMongo is there some possibility?
UPDATE:
I tried achieving with aggregation framework and following was the query:
$result = $collection->aggregate(array(
array(
'$match' => array(
"_id" => new MongoId("59f889e46803fa3713454b5d")
)
),
array(
'$project' => array(
'classes' => array(
'$filter' => array(
'input' => '$classes',
'as' => 'classItem',
'cond' => array(
'$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))
)
)
)
)
)
));
But i get this exception:
Sokil\\Mongo\\Exception\nMessage: Aggregate error: Unrecognized expression '$$classItem._id'\nFile:
So after posting the problem on the PHPMongo GitHub issues i found so far there is no implementation of $elemMatch. Author posted some interesting insights on this issue and now this issue is marked as enhancement for the future.
Furthermore i have tried aggregation framework and i am succesfully able to achieve the desired results i found that there was a mistake in the syntax of following expression (for full query see above in the question):
'$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))
I learned that expression of '$eq' shouldn't be a associative array rather each element in the expression should be a separate array item like this:
'$eq' => array('$$class._id', new MongoId("59f9d7776803faea30b895dd"))
So now my final aggregation query was like this:
$collection = $PHPMongoDBInstance->getCollection("Project");
$result = $collection->aggregate(array(
array(
'$match' => array(
"_id" => new MongoId('59f889e46803fa3713454b5d')
)
),
array(
'$project' => array(
'classes' => array(
'$filter' => array(
'input' => '$classes',
'as' => 'class',
'cond' => array(
'$eq' => array('$$class._id', new MongoId("59f9d7776803faea30b895dd"))
)
)
),
'projectName' => 1
)
)
));
Hope this will help people in future if they had similar problem like me as i tried finding solution and it wasn't there over the internet. I will try to update once there is a feature enhancement in PHPMongo of $elemMatch.

HHVM MongoDb aggregation seems like it doesn't work

I have some php script running on hhvm
I'm trying to get max value of numeric field from my collection in MongoDB 3.2
Here is my aggregation pipeline
$mongo = new \MongoDB\Driver\Manager(MONGODB_HOST);
$myCollection = new \MongoDB\Collection($mongo, "mydb.mycollection");
$pipeline = [
[
'$group' => [
'_id' => 'group_field',
'slId' => ['$max' => '$saleId']
],
]
];
$doc = $myCollection->aggregate($pipeline);
This pipeline perfectly works in mongo shell, but from php $doc contains all documents from my collection and no $group is applied to them
Maybe someone can help me with that?
The aggregation operation is returning all documents from your collection since you are specifying a constant value for the group by key, the string group_field. You need to prefix the group field with the $ character in your _id key value. So for example if your group by key is the name field, you can rewrite the aggregation pipeline as
$mongo = new \MongoDB\Driver\Manager(MONGODB_HOST);
$myCollection = new \MongoDB\Collection($mongo, "mydb.mycollection");
$group_field = '$name';
$pipeline = [
[
'$group' => [
'_id' => $group_field,
'slId' => ['$max' => '$saleId']
],
]
];
$doc = $myCollection->aggregate($pipeline);
Thanks to chridam's answer up here.
I don't know, but maybe this is some kind of magic
So, chridam's answer helped me with $group, so finally my results were grouped by $group_field. But slId still wasn't there. So, here is what i did and it helped:
$f = '$group_field';
$sl = ['$max' => '$saleId'];
$pipeline = array(
array(
'$group' => array(
'_id' => $f,
'slId' => $sl
),
)
);

Categories