Select Max() with "group by" in mongodb - mongodb

Please help me to convert this select sentence to mongodb:
Select Name, Max(Value) From table1 Group By Name
I read this document: http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group
but still dont know how to apply Max() method instead SUM() as that document.
Thank you.

I have created Mongo Collection as follows.
{ "_id" : ObjectId("4fb36bfd3d1c88bfa15103b1"), "name" : "bob", "value" : 5 }
{ "_id" : ObjectId("4fb36c033d1c88bfa15103b2"), "name" : "bob", "value" : 3 }
{ "_id" : ObjectId("4fb36c063d1c88bfa15103b3"), "name" : "bob", "value" : 7 }
{ "_id" : ObjectId("4fb36c0c3d1c88bfa15103b4"), "name" : "john", "value" : 2 }
{ "_id" : ObjectId("4fb36c103d1c88bfa15103b5"), "name" : "john", "value" : 4 }
{ "_id" : ObjectId("4fb36c143d1c88bfa15103b6"), "name" : "john", "value" : 8 }
{ "_id" : ObjectId("4fb36c163d1c88bfa15103b7"), "name" : "john", "value" : 6 }
Then by using the following code I group it by their name and max(value)
db.table1.group(
{key: {name:true},
reduce: function(obj,prev) {
if (prev.maxValue < obj.value) {
prev.maxValue = obj.value;
}
},
initial: { maxValue: 0 }}
);
The result is shown as
[
{
"name" : "bob",
"maxValue" : 7
},
{
"name" : "john",
"maxValue" : 8
}
]
It is much simpler with the aggregation framework. You can get the same result with the following code by using aggregation framework.
db.table1.aggregate([
{
$group:{_id:"$name", "maxValue": {$max:"$value"}}
}
]);

Using the Aggregation Framework:
db.table1.aggregate({$group:{'_id':'$name', 'max':{$max:'$value'}}},
{$sort:{'max':1}}).result

var myresult = db.table1.aggregate([{
$group: {
_id:"$Name",
value: { $max: "$Value" }
}
}]);
print(myresult)

Since MongoDB supports mapreduce below function should do.
db.employee.insert({name:"Tejas",Value:2})
db.employee.insert({name:"Tejas",Value:3})
db.employee.insert({name:"Varma",Value:1})
db.employee.insert({name:"Varma",Value:6})
var map=function(){
var key={name:this.name};
var value={value:this.Value};
emit(key,value);
};
var reduce=function(key,values){
var max=-1;
values.forEach(function(value){
if(max==-1){
max=value['value'];
}
if(max<value['value']){
max=value['value'];
}
});
return {max:max};
};
db.employee.mapReduce(map,reduce,{out:{inline:1}});

Related

How can I extract whole documents based on how they compare with their whole collection?

I'm trying to extract the latest available daily measurements from a "sparse" collection that might not have a measurement for every day. I'm interested in getting the whole original document as output. The collection contains several series of measurements identified by a unique id.
For example, given the following collection:
{ "date" : "2019-04-10", "id" : 1, "measurement" : 50 }
{ "date" : "2019-04-10", "id" : 2, "measurement" : 1 }
{ "date" : "2019-04-10", "id" : 3, "measurement" : 33 }
{ "date" : "2019-04-11", "id" : 1, "measurement" : 52 }
{ "date" : "2019-04-11", "id" : 3, "measurement" : 3 }
{ "date" : "2019-04-12", "id" : 1, "measurement" : 55 }
{ "date" : "2019-04-12", "id" : 2, "measurement" : 12 }
The above collection contains measurements for 3 ids. I'd like to retrieve the latest measurements for each id.
For example, the above collection should yield the following result:
{ "date" : "2019-04-12", "id" : 1, "measurement" : 55 }
{ "date" : "2019-04-12", "id" : 2, "measurement" : 12 }
{ "date" : "2019-04-11", "id" : 3, "measurement" : 3 }
So far, I'm able to extract the latest date for every ids with this:
db.control_subs.aggregate([ { $group : { _id : "$id", "last_date" : { $max : "$date" } } }, { $sort:{ "_id": 1 }} ])
But this, unfortunately, strips the actual measurement field from the output.
How could I obtain the desired output with a single MongoDB query?
You can try below aggregation query with $$ROOT operator:
db.control_subs.aggregate([
{
"$project":
{
"id": "$id",
"date": "$date",
"document": "$$ROOT" // save all fields for future usage
}
},
{
"$sort":
{ "date": -1
}
},
{
"$group":
{
"_id":{"id":"$id"},
"original_doc":{"$first":"$document"}
}
},
{
$project:
{
"original_doc.date":1, "original_doc.id":1, "original_doc.measurement":1, _id:0}
}
])
Output of above aggregation is
{ "original_doc" : { "date" : "2019-04-11", "id" : 3, "measurement" : 3 } }
{ "original_doc" : { "date" : "2019-04-12", "id" : 2, "measurement" : 12 } }
{ "original_doc" : { "date" : "2019-04-12", "id" : 1, "measurement" : 55 } }
Even you can also replace the original_doc with the help of $replaceRoot

Find minimum value on mongodb

I am trying to find out the student scored the minimum mark on the collection. I am not getting expected output. Your help would be appreciated:
> db.Student.find()
{ "_id" : ObjectId("5c8a3e85e8e2bcb1a75780c4"), "Name" : "Nandhi", "Mark" : 90 }
{ "_id" : ObjectId("5c8a3e85e8e2bcb1a75780c5"), "Name" : "Rajan", "Mark" : 80 }
{ "_id" : ObjectId("5c8a3e85e8e2bcb1a75780c6"), "Name" : "Raj", "Mark" : 75 }
Query:
> db.Student.aggregate([{$group:{_id:"Mark",avg_marks:{$min:1}}}])
Output
{ "_id" : "Mark", "avg_marks" : 1 }
Sort by mark and limit to 1
db.Student.find().sort({Mark:1}).limit(1)
Using aggregation
db.Student.aggregate(
[
{
$group:
{
_id: null,
minMark: { $min: "$Mark" }
}
}
])
You can use sort and limit
db.Student.find().sort({Mark:1}).limit(1)

Find from another find in mongodb

In Mysql I can do a Select from another Select.
So I would ask if I can do the same in Mongodb.
For more explanation, I need to retreive the transaction of the a specific userOwner with just the last dateTransaction in the history object of this collection.So if this userOwner isn't in the last history we shoudn't retreive this transaction.
I used at first this query:
#Query(value = "{'history':{'$elemMatch':{'userOwner': ?0}}}")
but it returns all the elements even those where this userOwner isn't with the last "dateTransaction".
So I aim to de a query that it returns for each transaction just the last dateTransaction with userOwner of the "history" array :
.find({},{dateTransaction: {$slice: 1} }).limit(1)
and after do another query from this one.
Anyone has an idea or examples.
Tnx
This is my Collection called "piece":
{
"_id" : ObjectId("1"),
"history" : [{
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-30T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-23T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("2"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("3"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}
As example the result for the userOwner 2 should be :
{
"_id" : ObjectId("2"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "3",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}{
"_id" : ObjectId("3"),
"transactions" : [{
"userOwner" : "2",
"dateTransaction" : ISODate("2016-05-26T00:00:00.000+0000"),
}, {
"userOwner" : "1",
"dateTransaction" : ISODate("2016-05-15T00:00:00.000+0000"),
}
]
}
it looks like your data is stored in one collection - so this is a kind of bad design as it needs more overhead to work with....
below aggregation query which has a lookup to the same collection to match data for user:2
var unwind = {
$unwind : "$history"
}
var matchUser = {
$match : {
"history.userOwner" : "2"
}
}
var lookUp = {
$lookup : {
from : "shm",
localField : "userOwner",
foreignField : "userOwner",
as : "t"
}
}
var unwindTransactions = {
$unwind : "$t"
}
var unwindTransactions2 = {
$unwind : "$t.transactions"
}
var match2 = {
$match : {
"t.transactions.userOwner" : "2"
}
}
var project = {
$project : {
_id : 0,
recordId : "$_id",
transactionId : "$t._id",
dateOfTransaction : "$history.dateTransaction",
userOwner : "$history.userOwner",
}
}
db.shm.aggregate([unwind,
matchUser,
lookUp,
unwindTransactions,
unwindTransactions2,
match2,
project
])
and as a result we have two records of user transactions
{
"recordId" : ObjectId("575e7e8b852cb76369c9e446"),
"transactionId" : ObjectId("575e7e8b852cb76369c9e447"),
"dateOfTransaction" : ISODate("2016-05-23T00:00:00.000Z"),
"userOwner" : "2"
},{
"recordId" : ObjectId("575e7e8b852cb76369c9e446"),
"transactionId" : ObjectId("575e7e8b852cb76369c9e448"),
"dateOfTransaction" : ISODate("2016-05-23T00:00:00.000Z"),
"userOwner" : "2"
}
Please consider split of that collection as in current form will give you a lot of headache when processing more complex queries

How to select and count distinct value of embedded array of collection in MongoDB?

Collection A have:
[
{
name: 'peter',
types: ['human', 'male', 'young']
},
{
name: 'mice',
types: ['male', 'young']
},
{
name: 'hen',
types: ['female', 'old']
}
]
I know how to get all distinct values of types but how to get its no. of appearance. How to extract it with Mongo query?
It would be great if you can show the solution in Doctrine QueryBuilder way.
Thanks
with aggregation framework you can sum apperance of all array elements using query provide below:
db.collection.aggregate([{
$project : {
_id : 0,
types : 1
}
}, {
$unwind : "$types"
}, {
$group : {
_id : "$types",
count : {
$sum : 1
}
}
}
])
and output:
{
"_id" : "human",
"count" : 1
}, {
"_id" : "old",
"count" : 1
}, {
"_id" : "male",
"count" : 2
}, {
"_id" : "young",
"count" : 2
}, {
"_id" : "female",
"count" : 1
}

Mongo map-reduce output, how to read results back?

I have a map-reduce query that "works" and does what I want however I have so far spectacularly failed to make use of my output data because I cannot workout how to read it back... let me explain... here is my emit:
emit( { jobid: this.job_id, type: this.type}, { count: 1 })
and the reduce function:
reduce: function (key, values) {
var total = 0;
for( i = 0; i < values.length; i++ ) {
total += values[i].count;
}
return { jobid: this.job_id, type:this.type, count: total};
},
It functions and the output I get in the results collection looks like this:
{ "_id" : { "jobid" : "5051ef142a120", "type" : 3 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051ef142a120", "type" : 5 }, "value" : { "count" : 43 } }
{ "_id" : { "jobid" : "5051f1a9d5442", "type" : 2 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f1a9d5442", "type" : 3 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f299340b1", "type" : 2 }, "value" : { "count" : 1 } }
{ "_id" : { "jobid" : "5051f299340b1", "type" : 3 }, "value" : { "count" : 1 } }
BUT HOW the hell do I issue a query that says find me all jobid entries by "jobid" whilst ignoring the type? I tried this intiailly, expecting two rows of output but got none!
db.mrtest.find( { "_id": { "jobid" : "5051f299340b1" }} );
I have also tried and failed with:
db.mrtest.find( { "_id": { "jobid" : "5051f299340b1" }} );
and whilst:
db.mrtest.find( { "_id" : { "jobid" : "5051f299340b1", "type" : 2 }} )
does produce one row of output as hoped for, changing it to this again fails to produce anything:
db.mrtest.find( { "_id" : { "jobid" : "5051f299340b1", "type" : { $in: [2] }}} )
I get the impression that you can't do such things with the _id field, or can you? I am thinking I need to re-organise my mr output instead but that feels like failing somehow ?!?!
Help!
PS: If anybody can explain why the count is contained in a field called "value", that would also be welcome!"5051f299340b1"
Have you tried:
db.mrtest.find( { "_id.jobid": "506ea3a85e126" })
That works for me!
db.mrtest.find( { "_id.jobid": "506ea3a85e126" })