3
votes

I am trying to query based on UUID with Spring Data - Mongo template. The generated query does not return the expected document. When I try to run the query in shell using new BinData(type, base64) it returns the documents. The generated query a uses {"$binary" : "base64", "$type" : "03} as the matching filter.

I have an Object that has id configured as UUID type. Here is the object type.

@Data
@NoArgsConstructor
@Document(collection = "person")
public class Person {
   @Id
   private UUID id;

   private String firstName;

   private String lastName;
   ...
}

Here is the custom repository implementation method.

...
Query findPersonQuery = new Query();

        findPersonQuery.addCriteria(Criteria.where("_id").is(personId));

        final Person person = mongoTemplate.find(findPersonQuery, Person.class);
// process and return person after
....

The above code seems to generate a parsed query as such when I pass in the UUID. UUID is a02b2900-b871-11e9-a2a3-2a2ae2dbcce4

{ "_id" : { "$eq" : { "$binary" : "6RFxuAApK6DkzNviKiqjog==", "$type" : "03" } } }

When I run this in mongo shell it returns nothing. In the repository it returns nothing.

However, when I put the following query in mongo shell I get the correct person object

db.getCollection('person').find({  "_id" : new BinData(3, "6RFxuAApK6DkzNviKiqjog==")})

I expected generated query to return the person with a UUID of a02b2900-b871-11e9-a2a3-2a2ae2dbcce4

Questions:

  1. What is the difference between $binary operator and BinData when passed into shell.
  2. How can I get spring data and mongoTemplate to generate the correct query. 2.1 Is it possible without writing a custom query?

I know we can do something like BasicQuery as shown below but is there a way to avoid it since we have to now provide a custom encoder of base 64 rather allow JPA style to convert UUIDs to persistence layer

final ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
        buffer.putLong(personId.getMostSignificantBits());
        buffer.putLong(personId.getLeastSignificantBits());
        final String base64PersonId = Base64.encodeBase64String(buffer.array());
  final String query = String.format("{ _id: new BinData(3,\"%s\")}", JSONObject.escape(username), base64PersonId);

        return new BasicQuery(query);
1
struggling with the same issue. That you for example :-) - Denis

1 Answers

0
votes

Change the UUID type to Object:

@Data
@NoArgsConstructor
@Document(collection = "person")
public class Person {
   @Id
   private Object id;

   private String firstName;

   private String lastName;
   ...
}