【问题标题】:Spring Mongo Aggregation Project FilterSpring Mongo 聚合项目过滤器
【发布时间】:2020-03-04 20:45:16
【问题描述】:

我在在 Mongo Shell 中工作的投影上实现过滤器时遇到问题。我有一个 Census 对象,其中包含员工列表。

{
   "_id": "ID",
   "name": "census1",
   "employees": [ {
      "eeId": "EE_ID1"
   }, 
   {
      "eeId": "EE_ID2"
   },
   {
      "eeId": "EE_ID3"
   }
}

实际上,这可能包含很多员工。所以我希望能够检索主要的 Census 对象和一部分员工。我已经实现了“切片”,所以这将通过他们的 eeId 检索一组员工。

这很好用:

db.census.aggregate( 
    [
        {
            $match: {
                "_id": ObjectId("ID1")
            }
        },
        {
            $project: {
                "censusName": 1,
                "employees" : {
                    $filter : {
                        input: "$employees",
                        as: "employees",
                        cond: { $in: [ "$$employees.eeId", ["EE_ID1", "EE_ID3"]] } 
                    }
                }
            }
        }
    ]
).toArray()

问题是,我无法用 Java 实现它。这里的 'employeeIds' 是我想要的 ID 字符串。

MatchOperation matchCensusIdStage = Aggregation.match(new Criteria("id").is(censusId));
ProjectionOperation projectStage = Aggregation.project("censusName")
        .and(Filter.filter("employees")
        .as("employees")
        .by(In.arrayOf(employeeIds).containsValue("employees.eeId")))
.as("employees");

Aggregation aggregation = Aggregation.newAggregation(matchCensusIdStage, projectStage);

return mongoTemplate.aggregate(aggregation, Census.class, Census.class).getMappedResults().get(0);

为此,不返回任何结果。我也试过用 BasicDBObject 实现它,但也卡在那里。

编辑(解决方法): 我确实得到了一个使用聚合的解决方案,但没有使用项目上的过滤器。这就是我所做的:

db.parCensus.aggregate( 
// Pipeline
[
    {
        $match: {
            "_id": ObjectId("ID1")
        }
    },
    {
        $project: {
            "_id": 0, "employee": "$employees"
        }
    },
    {
        $unwind: "$employee"
    },
    {
        $match: {
            "employee.eeId": { $in: ["EE_ID1", "EE_ID3"] }
        }
    }
]
).toArray()

Java 代码:

    MatchOperation matchCensusIdStage = Aggregation.match(new Criteria("id").is(censusId));
    ProjectionOperation projectStage = Aggregation.project("censusName").and("employees").as("employee");
    UnwindOperation unwindStage = Aggregation.unwind("employee");
    MatchOperation matchEmployeeIdsStage = Aggregation.match(new Criteria("employee.eeId").in(employeeIds));

    Aggregation aggregation = Aggregation.newAggregation(matchCensusIdStage, projectStage, unwindStage, matchEmployeeIdsStage);

我知道我可以在最后添加一个 $group 以将其放回一个 Census 对象,但我只是创建了一个单独的 CensusEmployee 对象来存储它。

【问题讨论】:

    标签: java spring mongodb aggregation-framework


    【解决方案1】:

    问题帖子中发布的聚合查询工作正常。聚合 ArrayOperators.In 语法的 MongoDB Spring Data API 不清楚。我无法实现基于此聚合的解决方案(网上也没有相关的答案)。

    但是,替代解决方案基于以下聚合查询 - 它工作正常。

    db.collection.aggregate( [
      { $unwind: "$employees" },
      { $match: { "employees.eeId": { $in: ["EE_ID1", "EE_ID3"] } } },
      { $group: { _id: "$_id", name: { $first: "$name" }, employees: { $push: "$employees" } } }
    ] )
    

    Java 代码:

    List<String> empsToMatch = Arrays.asList("EE_ID1", "EE_ID3");
    
    MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "test");
    Aggregation agg = newAggregation(
        unwind("employees"),
        match(Criteria.where("employees.eeId").in(empsToMatch )),
        group("_id")
            .first("name").as("name")
            .push("employees").as("employees")
     );
    
    AggregationResults<Document> results = mongoOps.aggregate(agg, "collection", Document.class);
    

    【讨论】:

    • 对,ArrayOperators.In 是我试图找到的解决方案。我将用我最终得到的工作来编辑我的问题,但我希望有人可以帮助解决如何使用 ArrayOperators.In。
    猜你喜欢
    • 2020-01-30
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-27
    • 2020-04-14
    • 1970-01-01
    相关资源
    最近更新 更多