如何在spring mongodb中检索数组中的匹配元素? [英] How to retrieve matching element in array in spring mongodb ?

查看:887
本文介绍了如何在spring mongodb中检索数组中的匹配元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图检索具有特定_id的文档和带有另一个特定_id的单个嵌入文档。

Im trying to retrieve a document with a specific '_id' and a single embedded document with another specific '_id'.

我的文档代表目录,它包含一系列课程。

my document is represent a catalog and it contains an array of courses.

示例数据:

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

在mongod我运行这个聚合查询,然后回到什么地方我希望:

In mongod I run this aggregation query, and get back what I wish for:

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

如前所述,我得到了返回我单个目录实例,其中包含一个课程实例。

As I mentioned earlier, I've get back I single catalog instance with a single course instance within.

在我的java repo中,我试图做同样的事情:

In my java repo, I was trying to do the same:

    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();

但不幸的是,我有一个带有空数组课程的'示例目录'的实例。

But unfortunately, I've got an instance of my 'example catalog' with empty array of courses.

在调试时,我发现在结果中,有两个返回的道具。
第一个是我使用的,名为 mappedResults (表示从mongoDB返回的转换对象) - 包含一个空数组的课程。
另一个是 rawResults ,(表示数据为 DBObject ) - 包含特定课程我查询

While debugging, I've found that inside results, there are two props that returns back. first one is what I've used, called mappedResults (represents the converted object returning from mongoDB) - contains an empty array of courses. the other one is the rawResults, (represents the data as DBObject) - contains the specific course I query for

我的Catalog类包含一个ArrayList(如果这有任何区别)。

请帮助并告诉我如何正确转换结果,或者如果我在代码中做错了什么。

Please help and let me know what should I do to convert the results properly, or if I did something wrong in my code.

推荐答案

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

You can try below options. The key is to preserve the structure when mapping the response.

常规查询:

使用 $ position 投影

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 阶段将用课程字段href =https://docs.mongodb.com/manual/reference/operator/aggregation/filter/\"rel =nofollow noreferrer> $ filter 值,同时保留所有现有属性。我在当前的春季版本中找不到任何 addFields 构建器。所以我必须使用 AggregationOperation 来创建一个新的。

You can use $addFields stage which will overwrite the courses field with the $filter value while keeping all the existing properties. I couldn't find any addFields builder in current spring version. So I have to use AggregationOperation to create a new one.

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 Version = 3.2 & Spring 1.5.2 Boot / Spring 1.10.1 Mongo。

这个想法仍然与上面相同,但这个管道使用 $ project 所以你必须添加你想保留的所有字段在最后的回应。还使用spring helper方法创建 $ filter 管道。

The idea is still same as above but this pipeline uses $project so you'll have to add all the fields that you want to keep in final response. Also used spring helper methods to create the $filter pipeline.

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 并添加课程字段才能获得弹簧图它正确。

You'll have to use $unwind and add a course field to have spring map it correctly.

这篇关于如何在spring mongodb中检索数组中的匹配元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆