1

I have the following working MongoDB aggregation shell command:

db.followrequests.aggregate([{
    $match: {
        _id: ObjectId("551e78c6de5150da91c78ab9")
    }
}, {
    $unwind: "$requests"
}, {
    $group: {
        _id: "$_id",
        count: {
            $sum: 1
        }
    }
}]);

Which returns:

{ "_id" : ObjectId("551e78c6de5150da91c78ab9"), "count" : 7 }

I need to implement this in Java, I am trying the following:

List<DBObject> aggregationInput = new ArrayList<DBObject>();

BasicDBObject match = new BasicDBObject();
match.put("$match", new BasicDBObject().put("_id",new ObjectId(clientId)));
aggregationInput.add(match);

BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$requests");
aggregationInput.add(unwind);

BasicDBObject groupVal = new BasicDBObject();
groupVal.put("_id", "$_id");
groupVal.put("count", new BasicDBObject().put("$sum", 1));

BasicDBObject group = new BasicDBObject();
group.put("$group", groupVal);
aggregationInput.add(group);

AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
for (DBObject result : output.results()) {
    System.out.println(result);
}

I am getting an exception:

mongodb the match filter must be an expression in an object.

Can you please help me identify the error in the above code. Thanks!

3 Answers 3

1

Try to print the value of aggregationInput and you will realise that .put() does not return a BasicDBObject but just the previous value associated to the key you update. Therefore, when you do:

match.put("$match", new BasicDBObject().put("_id",new ObjectId(clientId)));

You are actually setting $match to null, as new BasicDBObject().put("_id",new ObjectId(clientId)) returns null.

Update you code to something like:

List <DBObject> aggregationInput = new ArrayList <DBObject> ();

BasicDBObject match = new BasicDBObject();
BasicDBObject matchQuery = new BasicDBObject();
matchQuery.put("_id", new ObjectId());
match.put("$match", matchQuery);
aggregationInput.add(match);

BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$requests");
aggregationInput.add(unwind);

BasicDBObject groupVal = new BasicDBObject();
groupVal.put("_id", "$_id");
groupVal.put("count", new BasicDBObject().put("$sum", 1));

BasicDBObject group = new BasicDBObject();
group.put("$group", groupVal);
aggregationInput.add(group);

AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
for (DBObject result : output.results()) {
    System.out.println(result);
}

Or, slightly more readable, use the fluent BasicDBObjectBuilder:

final DBObject match = BasicDBObjectBuilder.start()
                                           .push("$match")
                                               .add("_id", new ObjectId())
                                           .get();
aggregationInput.add(match);

And it should work fine.

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

1 Comment

Excellent, thanks a ton, it works. Just had to do the same thing with group val for count also.
1

Each {} must be new DBObject. Use also .append(key,value) method to make more elegant.

Try this:

List<DBObject> pipeline = new ArrayList<DBObject>(Arrays.asList(
    new BasicDBObject("$match", new BasicDBObject("_id", 
        new ObjectId("551e78c6de5150da91c78ab9"))), 
    new BasicDBObject("$unwind", "$requests"),
    new BasicDBObject("$group", 
        new BasicDBObject("_id","$_id").append("count", new BasicDBObject("$sum", 1)))));

AggregationOutput output = followRequestsCol.aggregate(pipeline);
for (DBObject result : output.results()) {
    System.out.println(result);
}

Comments

0

This is the final working version, based on the above suggestions // Use mongodb aggregation framework to determine the count of followers Integer returnCount = 0; List aggregationInput = new ArrayList();

    BasicDBObject match = new BasicDBObject();
    BasicDBObject matchQuery = new BasicDBObject();
    matchQuery.put("_id", new ObjectId(clientId));
    match.put("$match", matchQuery);
    aggregationInput.add(match);

    BasicDBObject unwind = new BasicDBObject();
    unwind.put("$unwind", "$requests");
    aggregationInput.add(unwind);

    BasicDBObject groupVal = new BasicDBObject();
    groupVal.put("_id", null);
    BasicDBObject sum = new BasicDBObject();
    sum.put("$sum", 1);
    groupVal.put("count", sum);
    BasicDBObject group = new BasicDBObject();
    group.put("$group", groupVal);
    aggregationInput.add(group);

    AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
    for (DBObject result : output.results()) {
        returnCount = (Integer) result.get("count");
        break;
    }
    return returnCount;

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.