20

I need your help for using MongoDB aggregation framework with java driver. I don't understand how to write my request, even with this documentation.

I want to get the 200 oldest views from all items in my collection. Here is my mongo query (which works like I want in console mode):

db.myCollection.aggregate(
    {$unwind : "$views"},
    {$match : {"views.isActive" : true}},
    {$sort : {"views.date" : 1}},
    {$limit : 200},
    {$project : {"_id" : 0, "url" : "$views.url", "date" : "$views.date"}}
)

Items in this collection have one or many views. My question is not about the request result, I want to know the java syntaxe.

1
  • 1
    Show us what you have tried for now event if it isn't working. Do not expect SO to write your code for you Commented Jul 27, 2015 at 13:54

4 Answers 4

51

Finally found the solution, I get the same result than with the original request.

Mongo Driver 3 :

Aggregate doc

MongoCollection<Document> collection = database.getCollection("myCollection");

AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
        new Document("$unwind", "$views"),
        new Document("$match", new Document("views.isActive", true)),
        new Document("$sort", new Document("views.date", 1)),
        new Document("$limit", 200),
        new Document("$project", new Document("_id", 0)
                    .append("url", "$views.url")
                    .append("date", "$views.date"))
        ));

// Print for demo
for (Document dbObject : output)
{
    System.out.println(dbObject);
}

You can make it more readable with static import :
import static com.mongodb.client.model.Aggregates.*;.
See koulini answer for complet example.

Mongo Driver 2 :

Aggregate doc

Iterable<DBObject> output = collection.aggregate(Arrays.asList(
        (DBObject) new BasicDBObject("$unwind", "$views"),
        (DBObject) new BasicDBObject("$match", new BasicDBObject("views.isActive", true)),
        (DBObject) new BasicDBObject("$sort", new BasicDBObject("views.date", 1)),
        (DBObject) new BasicDBObject("$limit", 200),
        (DBObject) new BasicDBObject("$project", new BasicDBObject("_id", 0)
                    .append("url", "$views.url")
                    .append("date", "$views.date"))
        )).results();
    
// Print for demo
for (DBObject dbObject : output)
{
    System.out.println(dbObject);
}

Query conversion logic : Query conversion logic Thank to this link

Sign up to request clarification or add additional context in comments.

3 Comments

Which Document you use exactly, I use Mongo driver 3.4, and in this class : com.mongodb.DBCollection, there is only aggregate function which use DBObject not Document ? => public AggregationOutput aggregate(final List<? extends DBObject> pipeline)
It's a MongoCollection from com.mongodb.async.client. Where the method is : aggregate(List<? extends Bson> pipeline). And Document implements Bson, so everything is fine.
You saved my day.
7

It is worth pointing out, that you can greatly improve the code shown by the answers here, by using the Java Aggregation methods for MongoDB.

Let's take as a code example, the OP's answer to his own question.

AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
        new Document("$unwind", "$views"),
        new Document("$match", new Document("views.isActive", true)),
        new Document("$sort", new Document("views.date", 1)),
        new Document("$limit", 200),
        new Document("$project", new Document("_id", 0)
                    .append("url", "$views.url")
                    .append("date", "$views.date"))
));

We can rewrite the above code as follows;

import static com.mongodb.client.model.Aggregates.*;

AggregateIterable output = collection.aggregate(Arrays.asList(
                unwind("$views"),
                match(new Document("views.isActive",true)),
                sort(new Document("views.date",1)),
                limit(200),
                project(new Document("_id",0)
                        .append("url","$views.url")
                        .append("date","$views.date"))
));

Obviously, you will need the corresponding static import but beyond that, the code in the second example is cleaner, safer (as you don't have to type the operators yourself every time), more readable and more beautiful IMO.

1 Comment

do you have to iterate through the AggregateIterable in order for the aggregate pipeline to execute?
3

Using previous example as a guide, here's how to do it using mongo driver 3 and up:

MongoCollection<Document> collection = database.getCollection("myCollection");
AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
    new Document("$unwind", "$views"),
    new Document("$match", new Document("views.isActive", true))
));

for (Document doc : output) {
    ...
}

Comments

0

Here is a simple way to count employee by departmentId.. Details at: Aggregation using Java API

        Map<Long, Integer> empCountMap = new HashMap<>();

        AggregateIterable<Document> iterable = getMongoCollection().aggregate(Arrays.asList(
                new Document("$match",
                        new Document("active", Boolean.TRUE)
                                .append("region", "India")),
                new Document("$group",
                        new Document("_id", "$" + "deptId").append("count", new Document("$sum", 1)))));

        iterable.forEach(new Block<Document>() {
            @Override
            public void apply(final Document document) {
                empCountMap.put((Long) document.get("_id"), (Integer) document.get("count"));
            }
        });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.