mongodb aggregation match date - mongodb

I have data like
{
"_id" : ObjectId("5b63e593f033ab66fa25a142"),
"percent_change_1h" : 0.37,
"percent_change_24h" : -3.91,
"percent_change_7d" : -7.08,
"last_updated" : 1533273443,
"created_at" : "2018-08-03 05:18:11",
"updated_at" : "2018-08-03 05:18:11"
}
its have created_at date like this "2018-08-03 05:18:11"
but i can pass date in aggregation function like "2018-08-03"
data not get in this match
I can not use $gte or $lte becouse get only given date data
query is here
$date = "2018-08-15";
$filters = ['$match'=>[
'quotes'=>$quotes,
'created_at' => $date]
];
$join = ['$lookup'=>[
'from' => "cryptocurrencies_list",
'localField'=> "crypto_list_id",
'foreignField'=> "_id",
'as'=>"listdata"]
];
$limits = ['$limit'=>10];
$query = $detailscollection->aggregate([$filters,$join,$limits]);

You can try below aggregation
$detailscollection->aggregate([
[
'$addFields' => [
'date' => [
'$dateToString' => [
'date' => [
'$dateFromString' => [
'dateString' => '$created_at',
'timezone' => 'America/New_York'
]
],
'format' => '%Y-%m-%d'
]
]
]
],
[
'$match' => [
'date' => $date, 'quotes' => $quotes
]
]
])

Related

MongoDb v4.2.1 aggregation - How to use join in php 7 code

I am working on PHP7 with MongoDB 4.2.
I am trying to Join tables using aggregation.
I am able to do on mongo console.
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item", // field in the orders collection
foreignField: "item", // field in the items collection
as: "fromItems"
}
},
{
$replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project: { fromItems: 0 } }
])
and getting result as:
{ "_id" : 1, "item" : "almonds", "description" : "almond clusters", "instock" : 120, "price" : 12, "quantity" : 2 }
{ "_id" : 2, "item" : "pecans", "description" : "candied pecans", "instock" : 60, "price" : 20, "quantity" : 1 }
Same thing I want do in the PHP but not getting result:
My PHP code is:
<?php
public function demo_join() {
global $mng; // $mng = new MongoDB\Driver\Manager("mongodb://localhost:27017");
global $dbname;
$command = new MongoDB\Driver\Command([
'aggregate' => 'orders',
'pipeline' => [
['$lookup' => ["from" => "items","localField" => "items","foreignField" => "items","as" => "fromItems"]],
],
]);
//$cursor = $mng->executeCommand($dbname, $command);
try {
$cursor = $manager->executeCommand($dbname, $command);
} catch(MongoDB\Driver\Exception $e) {
echo $e->getMessage(), "\n";
exit;
}
return $cursor;
}
?>
and getting this error:
Uncaught Error: Call to a member function executeCommand() on null in $cursor = $manager->executeCommand($dbname, $command);
and some time
Uncaught MongoDB\Driver\Exception\CommandException: The 'cursor' option is required, except for aggregate with the explain argument in
Ok, I got the answer:
I added this line : 'cursor' => new stdClass
<?php
//mongo database join example
public function test_join() {
global $mng;
global $dbname;
$pipeline = [['$lookup' => ["from" => "items","localField" => "items","foreignField" => "items","as" => "fromItems"]]];
$aggregate = new \MongoDB\Driver\Command([
'aggregate' => 'orders',
'cursor' => new stdClass,
'pipeline' => $pipeline
]);
$cursor = $mng->executeCommand($dbname, $aggregate);
return $cursor;
}
?>
Now, I am able to get the result.

Fetch a value from an array in a MongoDB collection

Below is my MongoDB collection
{
"_id" : ObjectId("5b2a2ee19d332d0118b26dfe"),
"Name" : "Rock",
"Job" : [
{
"Id" : ObjectId("5b2b93c63629d0271ce366ae"),
"JobName" : "abc",
"JobTrack" : [
"123"
]
}
]
}
I want to fetch both ObjectId values
my $cursor = $custColl->find(
{ 'Job.JobName' => "abc", 'Job.JobTrack' => "123" },
{ '_id' => 1, 'Job.Id' => 1 }
);
while ( my $next = $cursor->next ) {
my $CustomerId = "$next->{_id}";
my $JobId = "$next->{'Job.Id'}";
say "$CustomerId => $JobId\n";
}
The result I got from above code as follows
5b2a2ee19d332d0118b26dfe =>
With this code I'm not able to get $JobId.
Assuming the query finds a document, $next is a Perl data structure that resembles your original JSON:
{
'Name' => 'Rock',
'_id' => bless( {
'value' => '5b2a2ee19d332d0118b26dfe'
}, 'MongoDB::OID' ),
'Job' => [
{
'JobName' => 'abc',
'JobTrack' => [
'123'
],
'Id' => bless( {
'value' => '5b2b93c63629d0271ce366ae'
}, 'MongoDB::OID' )
}
]
}
To get the job ID, you need to dereference that structure using Perl syntax, not MongoDB syntax:
my $JobId = "$next->{Job}[0]{Id}";
You need to access a specific element of the Job array. Because there is only one element in your example it must have an index of zero. Accordingly you need
my $JobId = "$next->{'Job.0.Id'}";

mongodb sorting group result

I am trying to get the first of each group, then I need to sort the resultset. I have achieved the first part but unable to sort the result. Here is what I have tried
Sample Data
{
"_id" : ObjectId("57f549e1831529409b000001"),"name" : "book1","author" : "abc","revision" : 1.0,
"published_on" : ISODate("2016-10-05T18:43:45.902Z"),"publisher" : "newpublisher"
},
{
"_id" : ObjectId("57f54a4483152940ad000001"),"name" : "book1","author" : "a1","revision" : 1.1,
"published_on" : ISODate("2016-10-05T18:45:24.436Z"), "publisher" : "newpublisher"
},
{
"_id" : ObjectId("57f54baa83152940c3000001"), "name" : "oldbook", "author" : "alice","revision" : 1.0,
"published_on" : ISODate("2016-10-05T18:51:22.484Z"),"publisher" : "newpublisher"
},
{
"_id" : ObjectId("57f54c4983152940c3000002"),"name" : "artoflearning","author" : "mike","revision" : 1.0,
"published_on" : ISODate("2016-10-05T18:54:01.585Z"),"publisher" : "oldpublisher"
},
{
"_id" : ObjectId("57f54c5883152940c3000003"),"name" : "artoflearning","author" : "mike","revision" : 1.1,
"published_on" : ISODate("2016-10-05T18:54:16.568Z"),"publisher" : "oldpublisher"
},
{ "_id" : ObjectId("57f54c6583152940c3000004"),"name" : "artoflearning","author" : "mike","revision" : 1.2,
"published_on" : ISODate("2016-10-05T18:54:29.848Z"),"publisher" : "oldpublisher"
},
{ "_id" : ObjectId("57f5513f8315294116000000"),"name" : "learning","author" : "mike","revision" : 2.0,
"published_on" : ISODate("2016-10-05T19:15:11.342Z"),"publisher" : "newpublisher"
}
I am getting latest revision (sort by revision in desc) group by name for a given publisher. I have used this query to achieve
Book.collection.aggregate([
{'$match' => {"publisher"=>"newpublisher"}},
{'$sort' => {'revision' => -1}},
{'$group' => {'_id' => '$name',
'revision' => {'$first' => '$revision'},
'id' => {'$first' => '$_id'},
'name' => {'$first' => '$name'},
'published_on' => {'$first' => '$published_on'},
'publisher' => {'$first' => '$publisher'}
}
},
{'$project' => {'_id' => '$id',
'revision' => '$revision',
'name' => '$name',
'published_on' => '$published_on',
'publisher' => '$publisher'
}
},
{'$skip' => 1},
{ '$limit' => 10 }
])
Since I need paginated result, I have applied skip and limit.
I have got this result
{"_id"=>{"$oid"=>"57f54a4483152940ad000001"}, "revision"=>1.1, "name"=>"book1", "published_on"=>"2016-10-05T18:45:24.436Z", "publisher"=>"newpublisher"},
{"_id"=>{"$oid"=>"57f5513f8315294116000000"}, "revision"=>2.0, "name"=>"learning", "published_on"=>"2016-10-05T19:15:11.342Z", "publisher"=>"newpublisher"}
Now I would like to sort by 'name' or 'published_on' columns. When I try to apply that on the result from above, I am getting error
Please advise
You didn't said what error you're getting, that would help. But you said
Now I would like to sort by 'name' or 'published_on' columns. When I try to apply that on the result from above, I am getting error
and by that I understand you added the sort after the limit. If you did that, it only sorts the skipped and limited results, in order to sort all results you must call the sort before skipping and limiting them, like:
Book.collection.aggregate([
{'$match' => {"publisher"=>"newpublisher"}},
{'$sort' => {'revision' => -1}},
{'$group' => {'_id' => '$name',
'revision' => {'$first' => '$revision'},
'id' => {'$first' => '$_id'},
'name' => {'$first' => '$name'},
'published_on' => {'$first' => '$published_on'},
'publisher' => {'$first' => '$publisher'}
}
},
{'$project' => {'_id' => '$id',
'revision' => '$revision',
'name' => '$name',
'published_on' => '$published_on',
'publisher' => '$publisher'
}
},
{'$sort' => {'name' => 1}},
{'$skip' => 1},
{'$limit' => 10 }
])
I added the documents you posted in a collection and ran this query and this is the result
[ { _id: 57f5513f8315294116000000,
revision: 2,
name: 'learning',
published_on: Wed Oct 05 2016 16:15:11 GMT-0300 (BRT),
publisher: 'newpublisher' },
{ _id: 57f54baa83152940c3000001,
revision: 1,
name: 'oldbook',
published_on: Wed Oct 05 2016 15:51:22 GMT-0300 (BRT),
publisher: 'newpublisher' } ]
And sorted by published_on:
{'$sort': {'published_on': 1}}
[ { _id: 57f54baa83152940c3000001,
revision: 1,
name: 'oldbook',
published_on: Wed Oct 05 2016 15:51:22 GMT-0300 (BRT),
publisher: 'newpublisher' },
{ _id: 57f5513f8315294116000000,
revision: 2,
name: 'learning',
published_on: Wed Oct 05 2016 16:15:11 GMT-0300 (BRT),
publisher: 'newpublisher' } ]

How to apply correctly $limit and $skip in subfields?

I'm starting with mongodb and I'm finding many difficulties with the following scheme.
{
"_id" : "AAA",
"events" : [
{
"event" : "001",
"time" : 1456823333
},
{
"event" : "002",
"time" : 1456828888
},
{
"event" : "003",
"time" : 1456825555
},...
]
}
I want to get the events sorted by date and apply limit and skip.
I'm using the following query:
$op = array(
array('$match' => array('_id' => $userId)),
array('$unwind' => '$events'),
array('$sort' => array('events.time' => -1)),
array('$group' => array('_id' => '$_id',
'events' => array('$push' => '$events')))
//,array('$project' => array('_id' => 1, 'events' => array('$events', 0, 3)))
//,array('$limit' => 4)
//,array('$skip' => 3)
);
$result= Mongo->aggregate('mycollection', $op);
I have tried everything to filter $project or $limit and $skip but none of it works.
How should I apply the limit and skyp conditions in events?
If I do not apply the conditions of "limit" above the result is ordered correctly.
Result:
{ "waitedMS":0,
"result":[
{
"_id":"AAA",
"events":[
{
"event":"002",
"time":1456828888,
},
{
"event":"003",
"time":1456825555,
},
{
"event":"001",
"time":1456823333,
},...
}
],
"ok":1
}
Order correctly but I can not limit the number of results for paging.

MongoDB Aggregation Framework

I have a document that's structured as follows:
{
'_id' => 'Star Wars',
'count' => 1234,
'spelling' => [ ( 'Star wars' => 10, 'Star Wars' => 15, 'sTaR WaRs' => 5) ]
}
I would like to get the top N documents (by descending count), but with only one one spelling per document (the one with the highest value). It there a way to do this with the aggregation framework?
I can easily get the top 10 results (using $sort and $limit). But how do I get only one spelling per each?
So for example, if I have the following three records:
{
'_id' => 'star_wars',
'count' => 1234,
'spelling' => [ ( 'Star wars' => 10, 'Star Wars' => 15, 'sTaR WaRs' => 5) ]
}
{
'_id' => 'willow',
'count' => 2211,
'spelling' => [ ( 'willow' => 300, 'Willow' => 550) ]
}
{
'_id' => 'indiana_jones',
'count' => 12,
'spelling' => [ ( 'indiana Jones' => 10, 'Indiana Jones' => 25, 'indiana jones' => 5) ]
}
And I ask for the top 2 results, I'll get:
{
'_id' => 'willow',
'count' => 2211,
'spelling' => 'Willow'
}
{
'_id' => 'star_wars',
'count' => 1234,
'spelling' => 'Star Wars'
}
(or something to this effect)
Thanks!
Your schema as designed would make using anything but a MapReduce difficult as you've used the keys of the object as values. So, I adjusted your schema to better match with MongoDB's capabilities (in JSON format as well for this example):
{
'_id' : 'star_wars',
'count' : 1234,
'spellings' : [
{ spelling: 'Star wars', total: 10},
{ spelling: 'Star Wars', total : 15},
{ spelling: 'sTaR WaRs', total : 5} ]
}
Note that it's now an array of objects with a specific key name, spelling, and a value for the total (I didn't know what that number actually represented, so I've called it total in my examples).
On to the aggregation:
db.so.aggregate([
{ $unwind: '$spellings' },
{ $project: {
'spelling' : '$spellings.spelling',
'total': '$spellings.total',
'count': '$count'
}
},
{ $sort : { total : -1 } },
{ $group : { _id : '$_id',
count: { $first: '$count' },
largest : { $first : '$total' },
spelling : { $first: '$spelling' }
}
}
])
Unwind all of the data so the aggregation pipeline can access the various values of the array
Flatten the data to include the key aspects needed by the pipeline. In this case, the specific spelling, the total, and the count.
Sort on the total, so that the last grouping can use $first
Then, group so that only the $first value for each _id is returned, and then also return the count which because of the way it was flattened for the pipeline, each temporary document will contain the count field.
Results:
[
{
"_id" : "star_wars",
"count" : 1234,
"largest" : 15,
"spelling" : "Star Wars"
},
{
"_id" : "indiana_jones",
"count" : 12,
"largest" : 25,
"spelling" : "Indiana Jones"
},
{
"_id" : "willow",
"count" : 2211,
"largest" : 550,
"spelling" : "Willow"
}
]