简体   繁体   中英

Why doesn't my Mongo aggregation work properly on nested document?

I have the following classes:

@Document(collection = "rCollection")
public class R{
    public R() {
    }
    @Id
    private String id;

    @TextIndexed(weight=2)
    private String fp;

    @TextIndexed(weight=1)
    private String sp;

    @DBRef
    @Indexed
    private P p;

    @DBRef
    private User user;
    private String date;
}

And:

@Document(collection = "pCollection")
public class P {

    public P() {}

    @Id 
    private String id;
}

What I would like to do is to search in RCollection and group the results based on the p element of the class. As the id in the P class is unique, I try to group the results based on p.id . I have the following code in my repository:

TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny(text);
MatchOperation match = Aggregation.match(criteria);
GroupOperation group = Aggregation.group("p.id");
Aggregation aggregation = Aggregation.newAggregation(match, group);

AggregationResults<finalResults> results = mongoTemplate.aggregate(aggregation, "rCollection", finalResults.class);

List<finalResults> result= results.getMappedResults();

System.out.println("size is: "+result.size());
System.out.println("output = "+result.get(0).toString());

The code works fine, when I use fp instead of p.id in the above code. But if I use p.id , I see that the result is null. result.size() is 1, but result.get(0).toString() is null. That is, the following output:

size is: 1
output = FinalResults [fp=null, sp=null]

Here is my finalResults class (it is actually exactly the same as the R class):

private class FinalResults{

    public finalResults() {
    }
    private String id;

    private String fp;
    private String sp;

    private P p;
    private User user;
    private String date;

    @Override
    public String toString() {
        return "FinalResults [fp=" + fp + ", sp=" + sp +"]";
    }
}

UPDATE : Sample data: Everything I have in rCollection :

{ 
"_id" : ObjectId("5e9db54c3b4b97129065b773"),
 "_class" : "com.main.tothepoint.model.R", 
"fp" : "hello\ni\nam\n",
"sp " : "hi",
"date" : "Mon Apr 20 16:44:28 CEST 2020",
"p" : DBRef("p", ObjectId("5e9db54c3b4b97129065b772")),
"user" : DBRef("user", ObjectId("5e5aa321383ba54434092e8d"))
}
{
 "_id" : ObjectId("5e9db7903b4b97129065b775"),
"_class" : "com.main.tothepoint.model.R", 
"fp " : "hi",
"sp " : "hello",
"date" : "Mon Apr 20 16:54:08 CEST 2020",
"p" : DBRef("p", ObjectId("5e9db7903b4b97129065b774")),
"user" : DBRef("user", ObjectId("5e6e567dc77ed32ab4ad796b"))
}
{
"_id" : ObjectId("5e9db7a73b4b97129065b777"),
"_class" : "com.main.tothepoint.model.R",
"fp" : "hi",
"sp" : "",
"date" : "Mon Apr 20 16:54:31 CEST 2020",
"p" : DBRef("p", ObjectId("5e9db7a73b4b97129065b776")),
"user" : DBRef("user", ObjectId("5e6e567dc77ed32ab4ad796b"))
}
{
"_id" : ObjectId("5e9ef7e04b6e5d338c02fda0"),
"_class" : "com.main.tothepoint.model.R",
"fp" : "hello",
"sp" : "",
"date" : "Tue Apr 21 15:40:48 CEST 2020",
"p" : DBRef("p", ObjectId("5e9ef7e04b6e5d338c02fd9f")),
"user" : DBRef("user", ObjectId("5e5aa321383ba54434092e8d"))
}
{
"_id" : ObjectId("5e9ef82b4b6e5d338c02fda3"),
"_class" : "com.main.tothepoint.model.R",
"fp " : "hello",
"sp" : "",
"date" : "Tue Apr 21 15:42:03 CEST 2020",
"p" : DBRef("p", ObjectId("5e9ef82b4b6e5d338c02fda2")),
"user" : DBRef("user", ObjectId("5e9ef81f4b6e5d338c02fda1"))
}

And the relevant part from pCollection :

{
 "_id" : ObjectId("5e9db54c3b4b97129065b772"),
"_class" : "com.main.tothepoint.model.P",
"p_name" : "Hisar",
"longitude" : 75.7216527,
"latitude" : 29.1491875
}


{
"_id" : ObjectId("5e9db7a73b4b97129065b776"),
"_class" : "com.main.tothepoint.model.P",
"p_name" : "Helsinki",
"longitude" : 24.9383791,
"latitude" : 60.16985569999999
}

The data has some more elements than the first part of my question, because I had tried to make my sample classes as small as possible. In my code, I would like to search for texts which can exist in fp and sp , for example, I search for "hi" and then I see the size of my result to be 2187.

The problem is here:

GroupOperation group = Aggregation.group("p.id");

In MongoDB shell, it would be like this:

{$group:{ _id:"$p._id" }}

As you see, your group stage is not complete. You need to accumulate fp and sp fields in Group stage. To acumulate all possible values for fp and sp fields, we need use $push (array with duplicate values) or $addToSet (set with unique values) opertors and add extra $unwind 's. stages.

TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny(text);
MatchOperation match = Aggregation.match(criteria);
GroupOperation group = Aggregation.group("p.id").push("fp").as("fp").push("sp").as("sp");
UnwindOperation unwindFp = Aggregation.unwind("fp");
UnwindOperation unwindSp = Aggregation.unwind("sp");
Aggregation aggregation = Aggregation.newAggregation(match, group, unwindFp, unwindSp);

AggregationResults<finalResults> results = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(R.class), FinalResults.class);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM