【问题标题】:How to get Spring Data Mongo Aggregations to work like they do with mongo如何让 Spring Data Mongo Aggregations 像使用 mongo 一样工作
【发布时间】:2020-01-02 02:52:51
【问题描述】:

我正在尝试使用 Spring Data Mongo 的聚合 API 进行简单的投影。

我想做的管道步骤是:

{
  $project : {
    "account._id" : 1,
    "account.position" : 1
  }
}

这是我尝试过的(以及大量其他调整,因为似乎没有任何效果):

ProjectionOperation project1 = Aggregation.project("account._id", "account.position");

但是,即使文档是这样说的:https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation.projection

由该投影呈现的实际文档最终看起来像:

{
  $project : {
    _id : "$account._id",
    position : "$account.position"
  }
}

这与我想要使用的投影完全不同。

有谁知道如何从 Spring Data Mongo Aggregation API 中获得我想要的投影,或者这是我需要报告的错误吗?


2019 年 8 月 29 日更新 - 添加更多数据以构建上下文:

涉及两个集合:“组”和“帐户” 一个组看起来像这样:

{
  _id : ObjectId("..."),
  name: ..., 
  ownerId: ObjectId("..."),
  other stuff...
}

帐户如下所示:

{
  _id : ObjectId("..."),
  position : "ABC",
   memberships : [{
    groupId: ObjectId("..."),
    otherstuff: ...,
  }],
  other stuff...
}

我的整个聚合看起来像这样,并在 mongodb shell 中按需要工作:(尝试获取属于特定用户拥有的任何组的成员的特定类型的所有帐户 ID 的列表)

groups.aggregate(
    {
        $match : {
            ownerId : ObjectId("XYZ"),
        }
    },
    {
        $lookup: {
               from: "accounts",
               localField: "_id",
               foreignField: "memberships.groupId",
               as: "account"
             }
    },
    {
        $project: {
            "account._id" : 1,
            "account.position" : 1
        }
    },
    {
        $unwind: "$account"
    },
    {
        $match: {
            "account.position" : "ZZZ"
        }
    },
    {
        $project: {
            _id : 0,
            accountId : "$account._id"
        }
    })

Java 版本的聚合:

MatchOperation match1 = Aggregation.match(
  where("ownerId").is(accountId));

LookupOperation lookupOperation = LookupOperation.newLookup()
  .from("accounts")
  .localField("_id")
  .foreignField("memberships.groupId")
  .as("account");

// This doesn't work correctly on nested fields:
ProjectionOperation project1 = Aggregation.project(
  "studentAccount._id", 
  "studentAccount.position");

Aggregation aggregation = Aggregation.newAggregation(
  match1,
  lookupOperation,
  project1,  
  unwind("account"),
  match(where("account.position").is("ZZZ")),
  project().and("account._id").as("accountId"));

【问题讨论】:

  • 您能否分享所涉及的域类型以及整个Aggregation,而不仅仅是一个项目操作。如果是类型化的Aggregation,属性将映射到字段名称。
  • @ChristophStrobl,我已在问题中添加了其他信息。

标签: mongodb aggregation-framework spring-data-mongodb


【解决方案1】:

如果你想让你的聚合工作看起来像 mongoshell 你可以这样尝试

Aggregation aggregation = Aggregation.newAggregation(
                match1,
                lookupOperation,
                // This's your project operation
                 new AggregationOperation() {
                    @Override
                    public Document toDocument(AggregationOperationContext aggregationOperationContext) {
                        Document project = new Document("$project",
                                new Document(
                                        "_id", "$account._id"
                                ).append("position", "$account.position")
                        );
                        return aggregationOperationContext.getMappedObject(project);
                    }
                },
                unwind("account"),
                match(where("account.position").is("ZZZ")),
                project().and("account._id").as("accountId")
        );

你可以用更通用的方式查看我的回答here

【讨论】:

  • 是的,我知道我可以这样做。我考虑将整个聚合编写为 json(因为这就是我开发管道的方式)并解析它以运行,但我试图弄清楚如何通过 Spring Aggregation API 来做到这一点。
猜你喜欢
  • 2016-05-15
  • 2018-06-11
  • 2014-08-19
  • 2014-05-15
  • 2013-06-24
  • 2016-10-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多