如何在Java中实现此MongoDB聚合

时间:2016-01-10 12:37:26

标签: java mongodb mongodb-query mongodb-java

我有以下工作MongoDB聚合shell命令:

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

返回:

  

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

我需要在Java中实现这一点,我正在尝试以下方法:

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);
}

我得到一个例外:

  

mongodb匹配过滤器必须是对象中的表达式。

请您帮我识别上述代码中的错误。谢谢!

3 个答案:

答案 0 :(得分:1)

尝试打印aggregationInput的值,您会发现.put()不会返回BasicDBObject,而只会返回与您更新的密钥相关联的上一个值。因此,当你这样做时:

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

您实际上将$match设置为null,因为new BasicDBObject().put("_id",new ObjectId(clientId))会返回null

将代码更新为:

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);
}

或者,稍微更具可读性,请使用流畅的BasicDBObjectBuilder

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

它应该可以正常工作。

答案 1 :(得分:1)

每个{}必须是新的DBObject。使用.append(key,value)方法也可以更加优雅。

试试这个:

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);
}

答案 2 :(得分:0)

这是最终的工作版本,基于以上建议         //使用mongodb聚合框架来确定关注者的数量         整数returnCount = 0;         列出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;