Caio César
Caio César

Reputation: 221

Get Average from Mongo Collection using Aggrerate

I am trying to learn how to use the Mongo in Java and have been able to make some simple queries but I have been having trouble with the aggregate operator.

The document structure is a simple one, as the following:

{
    "_id" : ObjectId("57dbe94f0507a4d8710ac5b2"),
    "name" : "Name1",
    "age" : 23
}
{
    "_id" : ObjectId("57dbe9750507a4d8710ac5b3"),
    "name" : "Name2",
    "age" : "String for examble"
}
{
    "_id" : ObjectId("57dbee630507a4d8710ac5b5"),
    "name" : "Name3",
    "age" : 24
}

All I want to do is get the average of the ages in the collection ( name example ).

Simply using mongo I can get the desirable result with the following consult:

db.example.aggregate([
    {
        $group: {
            _id: null, 
            averageAge: { $avg: "$age" }
        }
    }
]);

I have tried the following:

BasicDBObject groupFields = new BasicDBObject("_id", "null");
BasicDBObject media = new BasicDBObject("$avg", "$age");
groupFields.put("mediaIdade", media);
BasicDBObject group = new BasicDBObject("$group", groupFields );
AggregateIterable<org.bson.Document> agregate = db.getCollection("exemplo").aggregate(Arrays.asList (group));

Which is almost a direct translation but got a "java.lang.NoSuchMethodError: org.bson.codecs.BsonTypeClassMap.keys()Ljava/util/Set;" , unsurprisingly.

But I cannot translate that to Java. I have checked and found this question but could not understand it due to the use of opperators such as $unwind. So I'm trying to make query as simple as possible to better understand how the Java framework for aggregation works.

Can someone help?

Upvotes: 1

Views: 3223

Answers (3)

J.C. Gras
J.C. Gras

Reputation: 5442

Try this:

DBObject groupFields = new BasicDBObject( "_id", 0);
groupFields.put("average", new BasicDBObject( "$avg", "$age"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = db.getCollection("exemplo").aggregate(group);
Iterable<DBObject> list = output.results();

If required add a filter to the query you can add a match parameter:

DBObject match = new BasicDBObject();
match.put("age", new BasicDBObject("$gte", 25));
DBObject groupFields = new BasicDBObject( "_id", 0);
groupFields.put("average", new BasicDBObject( "$avg", "$age"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = db.getCollection("exemplo").aggregate(match, group);
Iterable<DBObject> list = output.results();

Upvotes: 0

s7vr
s7vr

Reputation: 75924

Try something like this.

MongoCollection<Document> dbCollection = db.getCollection("example", Document.class);
AggregateIterable<org.bson.Document> aggregate = dbCollection.aggregate(Arrays.asList(Aggregates.group("_id", new BsonField("averageAge", new BsonDocument("$avg", new BsonString("$age"))))));
Document result = aggregate.first();
double age = result.getDouble("averageAge");

Input:

{ "_id" : ObjectId("58136d6ed96cc299c224d529"), "name" : "Name1", "age" : 23 }
{ "_id" : ObjectId("58136d6ed96cc299c224d52a"), "name" : "Name2", "age" : 26 }
{ "_id" : ObjectId("58136d6ed96cc299c224d52b"), "name" : "Name3", "age" : 24 }

Output:

24.333333333333332

Upvotes: 2

Mike Shauneu
Mike Shauneu

Reputation: 3289

I noticed a small typo in your code:

db.getCollection("exemplo").aggregate(Arrays.asList (group));

Should be example instead of examplo

Also the easiest way to translate working mongo expression is using Document.parse method.

In your case it could be:

db.getCollection("exemplo").aggregate(Arrays.asList(
   Document.parse("{ $group: { _id: null, averageAge: { $avg: '$age' } } }")
));

Your impl also almost correct, two minor issues:

  • replace "null" string with just null value
  • Use "averageAge" instead of "mediaIdade"

    BasicDBObject groupFields = new BasicDBObject("_id", null);
    BasicDBObject media = new BasicDBObject("$avg", "$age");
    groupFields.put("averageAge", media);
    BasicDBObject group = new BasicDBObject("$group", groupFields );
    AggregateIterable<org.bson.Document> agregate = db.getCollection("exemple").aggregate(Arrays.asList (group));
    

To get result:

   agregate.first().getDouble("averageAge");

Upvotes: 0

Related Questions