java - 如何在 spring mongodb 中检索数组中的匹配元素?

标签 java spring mongodb aggregation-framework

我正在尝试检索具有特定“_id”的文档和具有另一个特定“_id”的单个嵌入式文档。

我的文档代表一个目录,其中包含一系列类(class)。

示例数据:

'_id': ObjectId('1111'),
'name': 'example catalog',
...
...
'courses': [
     { 
         '_id': ObjectId('2222'),
         'name': 'my course',
         ...
     },
     {
         ....
     }

在 mongod 中我运行这个聚合查询,并得到我想要的:

db.getCollection('catalogs').aggregate(
{ $match: { '_id': ObjectId('58e8da206ca4f710bab6ef74') } },
{ $unwind: '$courses' },
{ $match: { 'courses._id': ObjectId('58d65541495c851c1703c57f') } })

正如我之前提到的,我得到了一个目录实例,其中包含一个类(class)实例。

在我的 java 代码库中,我试图做同样的事情:

    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where(Catalog.ID_FIELD).is(catalogId)),
            Aggregation.unwind(Catalog.COURSES_FIELD, true),
            Aggregation.match(Criteria.where(Catalog.COURSES_FIELD + '.' + Course.ID_FIELD).is(embeddedCourseId))
    );
    AggregationResults<Catalog> results = mongoTemplate.aggregate(aggregation,
            Catalog.class, Catalog.class);

    List<Catalog> catalog  = results.getMappedResults();

但不幸的是,我有一个包含空类(class)数组的“示例目录”实例。

在调试时,我发现在 results 中,有两个返回的 props。 第一个是我用过的,称为 mappedResults(表示从 mongoDB 返回的转换后的对象)- 包含一个空的类(class)数组。 另一个是 rawResults,(将数据表示为 DBObject)- 包含我查询的特定类(class)

我的 Catalog 类包含一个 ArrayList(如果这有什么不同的话)。

请帮助并让我知道我应该怎么做才能正确转换结果,或者如果我在代码中做错了什么。

最佳答案

您可以尝试以下选项。关键是在映射响应时保留结构。

常规查询:

使用 $positional投影

Query query = new Query();
query.addCriteria(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74")).and("courses.id").is(new ObjectId("58d65541495c851c1703c57f")));
query.fields().include("name").position("courses", 1);
List<Course> courses = mongoTemplate.find(query, Course.class);

使用 $elemMatch投影

Query query = new Query();
query.addCriteria(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74")));
query.fields().include("name").elemMatch("courses", Criteria.where("_id").is(new ObjectId("58d65541495c851c1703c57f") ) );
List<Course> Course = mongoTemplate.find(query, Course.class);

聚合

Mongo 版本 >= 3.4 & Spring 1.5.2 Boot/Spring 1.10.1 Mongo。

您可以使用 $addFields将用 $filter 覆盖 courses 字段的阶段值,同时保留所有现有属性。我在当前的 spring 版本中找不到任何 addFields 构建器。所以我必须使用 AggregationOperation 来创建一个新的。

AggregationOperation addFields = new AggregationOperation() {
    @Override
    public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
        DBObject dbObject =
                new BasicDBObject("courses",
                        new BasicDBObject("$filter",
                                new BasicDBObject("input", "$$courses").
                                        append("as", "course").
                                        append("cond",
                                            new BasicDBObject("$eq", Arrays.<Object>asList("$$course._id", new ObjectId("58d65541495c851c1703c57f"))))));
        return new BasicDBObject("$addFields", dbObject);
    }
};

Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("_id").is(new ObjectId("58e8da206ca4f710bab6ef74"))),
            addFields
 );

Mongo 版本 = 3.2 & Spring 1.5.2 Boot/Spring 1.10.1 Mongo。

思路和上面一样,但是这个管道使用了$project所以你必须添加你想要保留在最终响应中的所有字段。还使用了 spring 辅助方法来创建 $filter 管道。

Aggregation aggregation = newAggregation(
     Aggregation.match(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74"))),
     Aggregation.project("name")
                 .and(ArrayOperators.Filter.filter("courses").as("course")                          
                 .by(ComparisonOperators.Eq.valueOf("course._id").equalToValue(new ObjectId("58d65541495c851c1703c57f")))
                    ).as("courses")
 );

Mongo 版本 <= 2.6

您必须使用 $unwind 并添加一个 course 字段才能让 spring 正确映射它。

关于java - 如何在 spring mongodb 中检索数组中的匹配元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43326515/

相关文章:

java - 从 JFrame GridBagLayout 获取组件大小

java - Hibernate 不创建我的表

python - 对象不是 JSON 可序列化的

具有客户端访问控制的 Mongodb docker 容器

java - 为什么 URL 没有完全解码?

Java 枚举 : implementing common methods, 避免重复

java - 如何使 * 运算符与 java 中的泛型变量一起使用? - 如果我知道变量是数字类型

java - Spring LibGDX And​​roid 应用程序中缺少 java.beans.Introspector

java - Webservice-Client : Common approach with Spring WS, JAXB 和一个 WSDL 文件?

mongodb - MongoDB 中的数组交集