0

I'm quite new to MongoDB and its interaction with Java. I'm using this driver

<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.2</version>
</dependency>

and I want to perform this aggregation query:

db.getCollection('COLLECTION').aggregate(
[
  {"$match": {"val.elem.0001": {"$exists":true}}},
  {"$project": {"FIELD_PATH": "$val.elem.0001"}},
  {$group: {_id:{"FIELD": {"$literal": "0001"}},
  "PATH": {"$addToSet": "$FIELD_PATH"}}}
]                                          
);

The Java code I've written is the following, however I'm not sure if I correctly used the addToSet method:

AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
new Document("$match", new Document("val.elem.0001",new Document("$exists",true))),
new Document("$project", new Document("FIELD_PATH","$val.elem.0001")),
new Document("$group", new Document("_id",new Document("FIELD", new Document("$literal", "0001"))
    .append("PATH", Accumulators.addToSet("$PATH", "$FIELD_PATH"))))));

It is correct? Because I can't print the result on screen if I add the "append" part. The error that returns is Can't find a codec for class com.mongodb.client.model.BsonField.

So, to summarize and make more readable and comprehensive what I've asked:

  • Is the Java representation of the query correct?
  • If so, why am I not able to print or access the result of the query?

1 Answer 1

2

Your usage of the API is incorrect.

Change your aggregation to the one below (stick with Document for expressions).

AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
       new Document("$match", new Document("val.elem.0001", new Document("$exists", true))),
       new Document("$project", new Document("FIELD_PATH", "$val.elem.0001")),
       new Document("$group", new Document("_id", new Document("FIELD", new Document("$literal", "0001"))).append("PATH", new Document("$addToSet", "$FIELD_PATH")))));

BsonField is a helper class primarily built to providea data holder for Accumulators which return key and Bson value pair. So it is not meant to be used as value type. When used with helper methods, it is converted into Document and serialized using the document codec.

You can rework your aggregation to use helper methods (Filters, Projections Accumulators & Aggregates).

AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
       Aggregates.match(Filters.exists("val.elem.0001")),
       Aggregates.project(Projections.computed("FIELD_PATH", "$val.elem.0001")),
       Aggregates.group( new Document("FIELD", new Document("$literal", "0001")), Accumulators.addToSet("PATH", "$FIELD_PATH"))));

You can further simplify the aggregation by using static imports.

import static com.mongodb.client.model.Accumulators.addToSet;
import static com.mongodb.client.model.Aggregates.group;
import static com.mongodb.client.model.Aggregates.match;
import static com.mongodb.client.model.Aggregates.project;
import static com.mongodb.client.model.Projections.computed;
import static java.util.Arrays.*;

AggregateIterable<Document> output = collection.aggregate(asList(
       match(Filters.exists("val.elem.0001")),
       project(computed("FIELD_PATH", "$val.elem.0001")),
       group( new Document("FIELD", new Document("$literal", "0001")), addToSet("PATH", "$FIELD_PATH"))));

See the documentation for more information.

Sign up to request clarification or add additional context in comments.

1 Comment

The first aggregation you've written does not work, beacause fails in the interpretation of $addToSet. However the others are perfect, so thanks a lot for helping me! I will use this approach when using aggregators.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.