使用 $lookup 和 $match 进行 MongoDB 聚合查询

问题描述 投票:0回答:1

背景:

我维护两个收藏:

Package
Module
。在
Module
集合中,每个文档都包含一个名为
packageId
的字段,它对应于
_id
集合中文档的
Package
字段。

来自Package集合的示例文档

  "_id": "660dc62edb464b62c8e34b3b",
  "workspaceId": "6606a50d59b56908f026a3ab",
  "packageUUID": "6605b2ee536675159c565857",
  "originPackageId": "6606a51359b56908f026a3b2",
  "version": "0.0.7",
  "latest": true
}

来自模块集合的示例文档

  "_id": "660dc62edb464b62c8e34b3c",
  "packageUUID": "6605b2ee536675159c565857",
  "packageId": "660dc62edb464b62c8e34b3b",
  "version": "0.0.7",
  "type": "QUERY_MODULE",
  "moduleUUID": "6605b324536675159c565869",
  "originModuleId": "6606a51359b56908f026a3bc"
}

我的用例:

当提供模块 ID 列表(即

_ids
集合中的
Module
)时,我的目标是统计满足以下条件的包的数量:

要么

originPackageId
字段不存在。 或者将
latest
字段设置为
true

我的尝试:

这是我尝试过的,但它总是返回

0

public long countPackages(List<String> moduleIds) {
        AggregationOperation matchModuleIds =
                Aggregation.match(Criteria.where(Module.Fields.id).in(moduleIds));

        LookupOperation lookupOperation = LookupOperation.newLookup()
                .from("package")
                .localField("packageId")
                .foreignField("_id")
                .as("packages");

        AggregationOperation unwindPackages = Aggregation.unwind("$packages"); // tried without `$` as well

        AggregationOperation matchConditions = Aggregation.match(new Criteria()
                .orOperator(
                        Criteria.where("packages.originPackageId").exists(false),
                        Criteria.where("packages.latest").is(true)));

        AggregationOperation groupByNull = Aggregation.group().count().as("total");

        Aggregation aggregation = Aggregation.newAggregation(
                matchModuleIds, lookupOperation, unwindPackages, matchConditions, groupByNull);

        List<Document> results = mongoTemplate
                .aggregate(aggregation, Module.class, Document.class)
                .getMappedResults();

        if (!results.isEmpty()) {
            Document resultDoc = results.get(0);
            return resultDoc.get("total", Long.class);
        } else {
            return 0L;
        }
    }

我感谢您在这方面的帮助。

java mongodb spring-boot aggregate
1个回答
0
投票

从您的代码看来 _id 被视为 ObjectId()。

匹配查询正在执行类似的操作(额外的“$oid”检查)

[{“$match”:{“_id”:{“$in”:[{“$oid”: "660dc62edb464b62c8e34b3c"}]}}}, { "$lookup" : { "from" : "包", “localField”:“packageId”,“foreignField”:“_id”,“as”: “包”}},{“$unwind”:“$packages”},{“$match”:{“$or”:[{ "packages.originPackageId" : { "$exists" : false}}, { "packages.latest" : true}]}}, { "$group" : { "_id" : null, "total" : { “$sum”:1}}}]

但是根据提供的文档,我可以看到“_id”是字符串。因此,在“Module”模型类中将 _id 声明为字符串会执行如下查询,该查询返回正确的结果

[{“$match”:{“_id”:{“$in”:[“660dc62edb464b62c8e34b3c”]}}},{ "$lookup" : { "from" : "包", "localField" : "packageId", "foreignField" : "_id", "as" : "packages"}}, { "$unwind" : "$packages"}, { "$match" : { "$or" : [{ "packages.originPackageId" : { "$exists" : false}}, { "packages.latest" : true}]}}, { "$group" : { “_id”:空,“总计”:{“$sum”:1}}}]

示例模块类:

@Id
@Field(targetType = FieldType.STRING)
private String _id;
private String packageUUID;
private String packageId;
private String version;
private String type;
private String moduleUUID;
private String originModuleId;
© www.soinside.com 2019 - 2024. All rights reserved.