Ticket: Get Comments - why is this code not working?

Can someone point out what’s wrong with the following code?
The error is java.lang.AssertionError: Comments list size does not match expected
Expected :147
Actual :41137

    public Document getMovie(String movieId) {
        if (!validIdValue(movieId)) {
            return null;
        }

        List<Bson> pipeline = new ArrayList<>();
        // match stage to find movie
        Bson match = Aggregates.match(Filters.eq("_id", new ObjectId(movieId)));
        pipeline.add(match);

        List<Variable<String>> let = new ArrayList<>();
        let.add(new Variable<>("id", "$_id"));

        List<Bson> lookupPipeline = new ArrayList<>();
        lookupPipeline.add(Aggregates.match(Filters.expr(Filters.eq("movie_id", "$$id"))));
        lookupPipeline.add(Aggregates.sort(descending("date")));

        Bson lookup = Aggregates.lookup("comments", let, lookupPipeline, "comments");
        pipeline.add(lookup);

        Document movie = moviesCollection.aggregate(pipeline).first();

        return movie;
    }

Hi :wave: @Yang_Li,

You can implement the following functions as follows:

private Bson buildLookupStage(){
  List<Variable<String>> let = new ArrayList<>();
  let.add(new Variable<String>("id", "$_id"));

  // lookup pipeline
  Bson exprMatch = Document.parse("{'$expr': {'$eq': ['$movie_id', '$$id']}}");

  Bson lookupMatch = Aggregates.match(exprMatch);
  List<Bson> lookUpPipeline = new ArrayList<>();
  // lookup sort stage
  Bson sortLookup = Aggregates.sort(Sorts.descending("date"));

  lookUpPipeline.add(lookupMatch);
  lookUpPipeline.add(sortLookup);
  return Aggregates.lookup("comments", let, lookUpPipeline, "comments");
}


public Document getMovie(String movieId){

  if (!validIdValue(movieId)) {
   return null;
 }

 List<Bson> pipeline = new ArrayList<>();
 // match stage to find movie
 Bson match = Aggregates.match(Filters.eq("_id", new ObjectId(movieId)));
 pipeline.add(match);

 // comments lookup stage
 Bson lookup = buildLookupStage();
 if(lookup != null) {
   pipeline.add(lookup);
 }

 Document movie = moviesCollection.aggregate(pipeline)
         .batchSize(1)
         .iterator().tryNext();
 return movie;
}

If you have any doubts, please feel free to reach out to us.

Regards,
Kushagra Kesav

Hi Kushagra,

Thank you for your comment. Do you know why using the Filters and Aggregates Builders don’t work here? In your code, you used Document.parse to parse the MQL to construct the BSON exprMatch object. I thought Builders are supposed to be used in order to simplify the CRUD operations for developers.

Lookup pipeline match stage using Builders

lookupPipeline.add(Aggregates.match(Filters.expr(Filters.eq("movie_id", "$$id"))));

Lookup pipeline match stage using Document.parse on MQL

Bson exprMatch = Document.parse("{'$expr': {'$eq': ['$movie_id', '$$id']}}");
Bson lookupMatch = Aggregates.match(exprMatch);

I think your code failed simply because you used movie_id rather than $movie_id. I do not think it is because you used the builders.

Builders are a convenience, but I never use them. I prefer Document.parse, often reading the query from a file, or I build everything somewhat like:

Document exprMatch = new Document( "$expr" ,
  new Document( "$eq" , Arrays.asList( [ "$movie_id" , "$$id" ] ) ) ;

It’s interesting that you don’t use Builders, because when exporting MQL from Compass/Atlas UI to Java code, the exported code also uses Document and List, not Builders. But this m220 class teaches people to use Builders.

I’ve tried $movie_id instead of movie_id, the code still fails.

I looked at the documentation for Filters.eq(), the only examples I could find were within the context of $match or find(), not within the $expr context.

Within $match and find(), we have

FieldName : { $eq : value }

but within $expr, the syntax is

$eq : [ ExpressionA , ExpressionB ]

I also found https://www.mongodb.com/docs/drivers/java/sync/v4.3/fundamentals/builders/aggregates/#full-join-and-uncorrelated-subqueries
where they seems to use new Document( “$eq” … ) when inside $expr rather than the builders.

May be someone more acquainted with Filters can enlighten both of us.

I do not use builders because I need to know the JS (mongosh) syntax anyway. Learning the builders is an extra step that I don’t feel I need. It is easier for me to map from JS syntax to java using Document class than using the Builders.

It is a personal taste, just like I prefer not to learn and use mongoose. An extra layer that hides (and sometimes prevents you from using) the raw power of mongodb.