简体   繁体   中英

How to do aggregate query with accumulators using mongodb driver in java

I'm quite new in 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 use correctly 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 resume and make more readable and comprehensive what I've asked:

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

Thanks in advance, if you need more informations, I'm ready to provide them.

Yous usage of api is incorrect.

Change your aggregation to 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 provide data holder for Accumulators which return key and Bson value pair. So it is not meant to be used as value type. When use with helper methods, it is converted into Document and serialized using 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 reduce 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"))));

For more information

http://mongodb.github.io/mongo-java-driver/3.4/driver/tutorials/aggregation/

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