Hi,
I’m dealing with below POJO for automatic serialization and deserialization using Mongo Java Driver:
@Builder
@Data
public class CaseDocument {
@BsonId
private long caseId;
private String customerId; //Nullable
private String addressId; //Nullable
@BsonCreator
public CaseDocument(...) {
// Constructor
}
}
Insert works fine. Retrieving the document by primary key and deserialization it into CaseDocument POJO works fine. Now I’m working on a query where I want to use projection to limit the number of fields returned but it throws an error. Below is how my query looks like:
FindIterable<CaseDocument> documents = mongoCollection.find(request.getQuery());
documents.projection(Projections.include("caseId", "customerId")); //Not including addressId
return documents.into(new ArrayList<>());
This gives me below error:
“org.bson.codecs.configuration.CodecConfigurationException: Could not construct new instance of: CaseDocument. Missing the following properties: [addressId]”
I can’t use @BsonIgnore on addressId because I want it to be persisted in the DB and retrieved for another query.
I saw there is BsonIgnoreExtraElements for C# for nothing similar for Java driver.
Hence my question is how can I achieve the desired result where Mongo Java Driver constructs the CaseDocument object without addressId field set?
I’m using 3.12 version of Mongo Java Driver.
Hello @Shubham_Gupta, welcome to the community.
Here is an appraoch.
You can get the result of the projection as List<Document>
(of org.bson.Document
) and use a mapper to map the fields from the Document
to the CaseDocument
POJO as shown below.
The mapper method can be like this:
// Maps an input Document to a CaseDocument and returns it.
static CaseDocument mapToCaseDocument(Document doc) {
CaseDocument caseDoc = new CaseDocument();
caseDoc.setCaseId(caseDoc.getLong("caseId"));
caseDoc.setCustomerId(caseDoc.getString("customerId"));
// Map other fields as needed (with any conversions, validations, etc.).
// Throw a runtime exception in case could not be mapped correctly.
return caseDoc;
}
So your modified code:
MongoCollection<Document> collection = db.getCollection("caseCollection");
List<CaseDocument> result = collection.find(request.getQuery())
.projection(Projections.include("caseId", "customerId"))
.into(new ArrayList<Document>())
.stream()
.map(doc -> mapToCaseDocument(doc))
.collect(Collectors.toList());
Note, the code uses Java driver v3.12 and MongoDB v4.2.
Thanks for replying Prasad. I understand that there are other ways to achieve it but I was looking for an out of the box solution but looks like that support is not there.
I myself achieved it by handling the serialization and deserialization using Jackson (Created a class DocumentUtils with two functions to convert Document to CaseDocument and vice versa).
A custom mapper though looks good here but it becomes hard to handle when there are 10+ fields in the POJO. Also the JSON returned by org.bson.Document contains bson identifiers like $numberLong which again requires extra handling.
I’ll raise an issue for it on Jira.