Mongodb Aggregation中的多个$ group with java

nir*_*rji 6 java mongodb mongodb-query aggregation-framework

这是我的查询,

db.product.aggregate([
{ $match : {categoryID : 4 } },
{ "$group" : { "_id" : { "productID": "$productID", 
                         "articleID": "$articleID", "colour":"$colour",
                         "set&size": { "sku" : "$skuID", "size" : "$size" },  
                        }, 
              }
},
{ "$group" : { "_id" : { "productID": "$_id.productID", "colour":"$_id.colour" }, 

   "size": { "$addToSet" : { "sku" : "$_id.set&size.sku", 
                                           "size" : "$_id.set&size.size" }
                         },   
 }
},
{"$project":{
     "_id":0,
     "productID":  "$_id.productID",
     "colour":"$_id.colour",
     "size":"$size",
     }
   },

   ]);
Run Code Online (Sandbox Code Playgroud)

通过在mongo shell上执行此查询,我得到了完美的输出.

产量

{
"_id": {
    "productID": "PRD1523",
    "colour": "GREEN"
},
"size": [
    {
        "sku": "ALT50095",
        "size": "S"
    },
    {
        "sku": "ALT50096",
        "size": "XL"
    }
]
}
{
"_id": {
    "productID": "PRD1523",
    "colour": "RED"
},
"size": [
    {
        "sku": "ALT50094",
        "size": "M"
    },
    {
        "sku": "ALT50093",
        "size": "S"
    }
]
}
Run Code Online (Sandbox Code Playgroud)

但是当我使用我的java代码时,它会给出异常.

这是上面查询的java代码,

DBCollection table = mongoTemplate.getCollection(collection_name);

    BasicDBObject matchTopics = new BasicDBObject();
    matchTopics.put("categoryID", 4);

    DBObject groupSameIdEntities = new BasicDBObject("_id", new BasicDBObject("productID", "$productID")
            .append("articleID", "$articleID").append("colour", "$colour")
            .append("set&size", new BasicDBObject("sku", "$skuID").append("size", "$size")));

DBObject secondGroup = new BasicDBObject("_id", new BasicDBObject("colour", "$_id.colour").append("productID",
            "$_id.productID").append(
            "size",
            new BasicDBObject("$addToSet", new BasicDBObject("sku", "$_id.set&size.sku").append("size",
                    "$_id.set&size.size"))));

AggregationOutput output = table.aggregate(new BasicDBObject("$match", matchTopics), new BasicDBObject(
            "$group", groupSameIdEntities), new BasicDBObject("$group", secondGroup));
Run Code Online (Sandbox Code Playgroud)

例外

HTTP状态500 - 请求处理失败; 嵌套异常是com.mongodb.CommandFailureException:{"serverUsed":"127.0.0.1:27017","errmsg":"异常:无效的运算符'$ addToSet'","code":15999,"ok":0.0}

我无法弄清楚如何解决这个错误.

Bla*_*ven 4

通常,最好的方法是独立于调用方法来定义完整的聚合管道,并遵循与您在此处找到并使用的 JSON 示例中相同的结构和缩进规则。

这样,就可以更容易地看出哪里偏离了结构:

List<DBObject> pipeline = Arrays.<DBObject>asList(
    new BasicDBObject("$match",new BasicDBObject("categoryID", 4)),
    new BasicDBObject("$group",
        new BasicDBObject("_id",
            new BasicDBObject("productID","$productID")
                .append("articleID", "$articleID")
                .append("colour", "$colour")
                .append("size",
                    new BasicDBObject("sku","$skuID")
                        .append("size","$size")
                )
        )
    ),
    new BasicDBObject("$group",
        new BasicDBObject("_id",
            new BasicDBObject("productID","$_id.productID")
                .append("articleID", "$_id.articleID")
                .append("colour", "$_id.colour")
        )
        .append("size",new BasicDBObject("$push","$_id.size")
    ),
    new BasicDBObject("$project",
        new BasicDBObject("_id",0)
        .append("productID","$_id.productID")
        .append("colour","$_id.colour")
        .append("size",1)
    )
);
Run Code Online (Sandbox Code Playgroud)

另请注意此处的一些简化命名并使用$push而不是$addToSet。最后一个通常是因为您已经通过将其包含在第一$group阶段中来确定唯一值,因此 an$addToSet在这里不会做任何有价值的事情,实际上会从早期阶段的结果中删除任何固有的顺序,或者如果您故意订购了。

从这个意义上讲,您当然可以缩短为单个,$group就像$addToSet执行它自己的“不同”操作一样:

List<DBObject> pipeline = Arrays.<DBObject>asList(
    new BasicDBObject("$match",new BasicDBObject("categoryID", 4)),
    new BasicDBObject("$group",
        new BasicDBObject("_id",
            new BasicDBObject("productID","$productID")
                .append("articleID", "$articleID")
                .append("colour", "$colour")
        )
        .append("size",new BasicDBObject("$addToSet",
            new BasicDBObject("sku","$skuID")
                .append("size","$size")
        )
    )
);
Run Code Online (Sandbox Code Playgroud)

我还建议删除最后一个,$project因为它本质上需要传递所有结果并更改所有存在的文档。这只是添加到通常在客户端上可以更好处理的处理。

一般来说,聚合管道阶段越少越好,除非发生重大事件,否则另一个软件层可能比数据库服务器更好地处理它。