java MongoTemplate 聚合项目嵌套文档

java MongoTemplate aggregate with project nested document

我有一个文件。

{
"errors" : [
    {
        "priority" : 3,
        "category" : "aaa"
        "other":"nothing"
    },
    {
        "priority" : 4,
        "category" : "bbb"
        "other":"nothing"
    },
    {
        "priority" : 2,
        "category" : "ccc"
        "other":"nothing"
    },
    {
        "priority" : 3,
        "category" : "ddd"
        "other":"nothing"
    },
    {
        "priority" : 2,
        "category" : "eee"
        "other":"nothing"
    }
    ],
"file_name" : "xxx.json",
"vehicle_id" : "esdf",
"day" : "2022-03-08"
}

我用js客户端执行命令

db.wty_test.aggregate({
    $project: {
        '_id': 0, 'errors.priority': 1, 'errors.category': 1, 'file_name': 1, 'vehicle_id': 1,
    }
})

我得到了我想要的结果。 错误是一个包含对象的数组。

现在我需要用java客户端(springboot-data-mongo)覆盖这个命令。这是我的 java 代码。

import org.springframework.data.mongodb.core.MongoTemplate;
...
Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("errors.priority", "errors.category", "file_name", "vehicle_id"));
mongoTemplate.aggregate(aggregation, "wty_test", HashMap.class).getMappedResults();

优先级和类别没有错误。

如何使用java得到和js一样的结果?

我试试 nested.But 这不是我想要的。


您想使用 nested() 函数,如下所示:

AggregationOperation project = Aggregation.project("file_name", "vehicle_id").
    and("errors").nested(Fields.fields("priority","category"))

Aggregation aggregation = Aggregation.newAggregation(project);

这是获得所需结果的方法。

Document projectn = new Document("$project", 
                        new Document("_id", 0L)
                        .append("file_name", 1L)
                        .append("vehicle_id", 1L)
                        .append("errors", 
                            new Document("$map", 
                                new Document("input", "$errors")
                                .append("in", 
                                    new Document("priority", "$$this.priority")
                                    .append("category", "$$this.category")
                                )
                            )
                        )
                    );

List<Document> pipeline = Arrays.asList(projectn);
List<Document> results = mongoOps.getCollection("collection_name")
                                 .aggregate(pipeline)
                                 .into(new ArrayList<>());

注意这里使用了MongoDBJavaDriverAPI查询语法,而Documentorg.bson.Document。将本机查询转换为 Java 驱动程序使用 $map 聚合数组运算符(看起来这就是(可能唯一的)方式)。

使用 MongoTemplate.aggregate 代码是:

    Aggregation agg = newAggregation(
            project() 
            .and( 
                VariableOperators.Map.itemsOf("errors")
                    .as("e")
                    .andApply(ctx -> new Document("priority", "$$e.priority").append("category", "$$e.category") ))
            .as("errors")
            .andExclude("_id")
            .andInclude("file_name", "vehicle_id")
    );

    AggregationResults<Document> results = mongoOps.aggregate(agg, "collection_name", Document.class);


替代方法:

如果您的查询只是关于 投影,您可以使用 MongoTemplate#find 方法使用以下查询。这更容易构建和理解:

db.collection.find(
    {}, // your query filter
    { _id: 0, 'errors.category': 1, 'errors.priority': 1, file_name: 1, vehicle_id: 1 }
)

它的 MongoTemplate 版本:

Query query = new Query();
query.fields()
     .include("errors.priority", "errors.category", "file_name", "vehicle_id")
     .exclude("_id");
List<Document> results = mongoOps.find(query, Document.class, "collection_name");