I'm writing a query to search for users created at specific date e.g.
$date = '2018-05-02 15:46:41.000Z';
User::raw(function ($col) use($date) {
return $col->aggregate([
['$match' =>
'created_at' => ['$gte' => new \MongoDB\BSON\UTCDateTime(strtotime($date))]
]
]);
});
Given an sample data like
{
"_id" : ObjectId("5ae9dd61ef7a5754f159c656"),
"name" : "Effie Larkin",
"created_at" : ISODate("2018-05-02 15:46:41.000Z"),
}...
Expected result should be
{
"users" : [
"_id" : {"$oid": "5ae9dd61ef7a5754f159c656"},
"name" "Effie Larkin",
"created_at" : "2018-05-02 15:46:41"
]
}...
But I get an empty json array []. I think the problem is in UTCDateTime function but I don't how to pass dateTime to it. I want to pass a time interval like 1 week ago or yesterday etc... if anyone can help me will be much appreciated, thanks
Update, the example below fixed it
$date = '2018-05-02';
User::raw(function ($col) use($date) {
return $col->aggregate([
['$match' =>
'created_at' => ['$gte' => new \MongoDB\BSON\UTCDateTime(strtotime($date)*1000)]
]
]);
});
Related
I have data stored in the following format in MongoDB:
[
{
meta: {
id: 1
},
data: {
date: "03/01/2020"
}
}
],
[
{
meta: {
id: 1
},
data: {
date: "12/19/2019"
}
}
]
And I want to use PHP to get all entries that are greater than or equal to the current date, and less than or equal to the current date plus 6 months.
To do that, my query looks like this:
$query = [
'meta.id' => 1,
'$expr' => [
'$and' => [
[
'$gte' =>
[
['$dateFromString' => ['dateString' => '$data.date']],
time()
]
],
[
'$lte' =>
[
['$dateFromString' => ['dateString' => '$data.date']],
strtotime('+6 months')
]
]
]
]
];
With this query, I should get back the first entry, with a date of "03/01/2020", however I get back no results.
I've also tried using 'format' in the dateString but it doesn't appear to be supported yet, as it gives me an error.
How can I get this query to work correctly?
I'm trying to build an aggregation query in Parse's PHP SDK, and I'm stuck in the "lookup" area, I saw a JS example regarding this but it doesn't work in my case.
I have a table of users, which contains a "Tags" field of type Array, the array is actually an array of pointers, that point to a separate Tag class.
What I'm trying to achieve is to list most popular Tags based on their usage, so basically I need to query the users class and group the Tags that exist in the array, I already achieved this, but I'm stuck with the lookup part, the query currently returns an array of Tags pointers, what I want is to pull the object of those pointers.
Here's what I have currently:
$query = new ParseQuery('_User');
$pipeline = [
'project' => ['tags' => 1],
'unwind' => '$tags',
'group' => [
'objectId' => '$tags.objectId',
'count' => ['$sum' => 1]
],
'sort' => [ 'count' => -1],
'limit' => 10,
];
try {
return $query->aggregate($pipeline);
} catch (ParseException $ex) {
return $ex->getMessage();
}
And here's a snippet of what the _User collection looks like:
{
"_id" : "5BuBVo2GD0",
"email" : "test#test.com",
"username" : "test#test.com",
"lastname" : "Doe",
"firstname" : "John",
"_created_at" : ISODate("2017-01-23T09:20:11.483+0000"),
"_updated_at" : ISODate("2019-02-15T02:48:30.684+0000"),
"tags" : [
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "St2gzaFnTr"
},
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "LSVxAy2o74"
}
],
"_p_country" : "Country$4SE8J4HRBi",
}
And the Tag collection looks like this:
{
"_id" : "St2gzaFnTr",
"name" : "Music",
"_created_at" : ISODate("2018-10-22T20:00:10.481+0000"),
"_updated_at" : ISODate("2018-10-22T20:00:10.481+0000")
}
Any help would be appreciated!
Thanks in advance
Not sure if this is a direct answer, but here's a working aggregation on tags sorting for freq...
public function tagHistogram(Request $request, Response $response, array $args): Response {
$pipeline = [
'unwind' => '$tags' ,
'sortByCount' => '$tags',
'limit' => 1000,
];
$query = new ParseQuery('Product');
$result = $query->aggregate($pipeline);
$result = array_map(
function ($e) {
$e['name'] = $e['objectId'];
unset($e['objectId']);
return $e;
},
$result
);
return $response->withJson($result);
}
Below is my sample mongodb collection
{
"_id" : ObjectId("57ed32f4070577ec56a56b9f"),
"log_id" : "180308",
"issue_id" : "108850",
"author_key" : "priyadarshinim_contus",
"timespent" : NumberLong(18000),
"comment" : "Added charts in the dashboard page of the application.",
"created_on" : "2017-08-16T18:22:04.816+0530",
"updated_on" : "2017-08-16T18:22:04.816+0530",
"started_on" : "2017-08-16T18:21:39.000+0530",
"started_date" : "2017-08-02",
"updated_date" : "2017-08-02",
"role" : "PHP",
"updated_at" : ISODate("2017-09-29T15:27:48.069Z"),
"created_at" : ISODate("2017-09-29T15:27:48.069Z"),
"status" : 1.0
}
I need to get records with help of started_date , by default I will give two dates in that i will check $gt and $lt of started date .
$current_date = '2017-08-31';
$sixmonthfromcurrent ='2017-08-01';
$worklogs = Worklog::raw ( function ($collection) use ($issue_jira_id, $current_date, $sixmonthfromcurrent) {
return $collection->aggregate ( [
['$match' => ['issue_id' => ['$in' => $issue_jira_id],
'started_date' => ['$lte' => $current_date,'$gte' => $sixmonthfromcurrent]
]
],
['$group' => ['issue_id' => ['$push' => '$issue_id'],
'_id' => ['year' => ['$year' => '$started_date'],
'week' => ['$week' => '$started_date'],'resource_key' => '$author_key'],
'sum' => array ('$sum' => '$timespent')]
],
[ '$sort' => ['_id' => 1]
]
] );
} );
If I run this query I am getting this type of error:
Can't convert from BSON type string to Date
How to rectify this error?
The only field in your $group that I see as troubling is the field week.
The year you could extract by doing a $project before your $group aggregation:
$project: {
year: { $substr: [ "$started_date", 0, 4 ] },
issue_id: 1,
author_key: 1,
timespent: 1
}
if you know that the date string will always come at this format. Of course you cannot do a substr operation for finding out the week.
It would be easy though if your field started_date would be an actual ISODate(), then you could use exactly what you wrote as you probably already saw in the documentation.
If you need the field week very bad, which I imagine you do, then I'd suggest you convert your field started_date to an ISODate().
You can do that with a bulkWrite:
db = db.getSiblingDB('yourDatabaseName');
var requests = [];
db.yourCollectionName.find().forEach(doc => {
var date = yourFunctionThatConvertsStringToDate(doc.started_date);
requests.push( {
'updateOne': {
'filter': { '_id': doc._id },
'update': { '$set': {
"started_date": date
} }
}
});
if (requests.length === 500) {
db.yourCollectionName.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.yourCollectionName.bulkWrite(requests);
}
Load this script directly on your mongodb server and execute there.
Hope this helps.
I am at my first steps with mongoDB and php, trying to figure out how aggregations works. I have an approximate idea on how to use them from the command line but I am trying to translate this for the php driver. I am using the restaurants dexample DB, a list of records like this
{
"_id" : ObjectId("59a5211e107765480896f3f8"),
"address" : {
"building" : "284",
"coord" : [
-73.9829239,
40.6580753
],
"street" : "Prospect Park West",
"zipcode" : "11215"
},
"borough" : "Brooklyn",
"cuisine" : "American",
"grades" : [
{
"date" : ISODate("2014-11-19T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2013-11-14T00:00:00Z"),
"grade" : "A",
"score" : 2
},
{
"date" : ISODate("2012-12-05T00:00:00Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-05-17T00:00:00Z"),
"grade" : "A",
"score" : 11
}
],
"name" : "The Movable Feast",
"restaurant_id" : "40361606"
}
I just want to count how many restaurants for location, what I am doing is
$client = new MongoDB\Client("mongodb://localhost:27017");
$collection = $client->myNewDb->restaurants;
$results = $collection->aggregate(
[
'name' => '$name'
],
[
'$group' => [
'cuisine' => ['sum' => '$sum']
]
]
);
and I am getting this error
Fatal error: Uncaught exception 'MongoDB\Exception\InvalidArgumentException'
with message '$pipeline is not a list (unexpected index: "name")'
any idea? I can't find any good documentation on php.net.
thanks
M
Just take a look into documentation, and you will see, that the pipelines must be passed as an array.
The aggregate method accepts two parameters $pipelines and $options (public function aggregate(array $pipeline, array $options = [])).
Also as was mentioned before, the $group must have the _id element.
Groups documents by some specified expression and outputs to the next
stage a document for each distinct grouping. The output documents
contain an _id field which contains the distinct group by key. The
output documents can also contain computed fields that hold the values
of some accumulator expression grouped by the $groupās _id field.
$group does not order its output documents.
https://docs.mongodb.com/manual/reference/operator/aggregation/group/
So your code must look like this:
$results = $collection->aggregate([
[
'$group' => [
'_id' => '$cuisine',
'sum' => ['$sum' => 1],
'names' => ['$push' => '$name']
]
]
]);
This code groups documents by cuisine element, counts the items and collects all name values into array.
i have mongodb 1 collections structure like this-
{
"_id" : ObjectId("54d34cb314aa06781400081b"),
"entity_id" : NumberInt(440),
"year" : NumberInt(2011),
}
{
"_id" : ObjectId("54d34cb314aa06781400081e"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2007),
}
{
"_id" : ObjectId("54d34cb314aa06781400081f"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2008),
}
{
"_id" : ObjectId("54d34cb314aa067814000820"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2009),
}
{
"_id" : ObjectId("54d34cb314aa067814000827"),
"entity_id" : NumberInt(489),
"year" : NumberInt(2009),
}
so in output i want that i should get "entity_id" with max "year" only .(suppose with "488" entity_id "year" should be 2009).
i have tried writing query
$fin_cursor = $db->command(array(
"distinct" =>"Profit_and_Loss",
"key" =>'entity_id',
"query" => array(array('$and'=>$financial_pl_search_array),array('$sort'=>array("year"=>-1))),
));
in output i want 2 fields "entity_id" and "year".
can anyone suggest me best way of doing it.
Thanks in advance.
You're better of using .aggregate() to do this. It's also a direct method on the collection objects in modern versions of the driver:
$result = $db->collection('Profit_and_loss')->aggregate(array(
array( '$group' => array(
'_id' => '$entity_id',
'year' => array( '$max' => '$year' )
))
));
The .distinct() command only runs over a single field. Other forms require JavaScript evaluation as you have noted and run considerably slower than native code.