Hibernate OGM result of aggregation query - java

I am using hibernate ogm 5.1 in my application and I construct this query. This query
String query = "db.SWMessages.aggregate( [ {0}, {1} ] )";
Document q1 = new Document("$match",new Document("messageUuid",new
Document("$ne" , id.toString())));
Document q2 = new Document("$group", new Document("_id",
"$localReference").append("max", new Document("$max","$creationDate")));
Object[] param = { q1.toJson(), q2.toJson() };
String nativeQuery = MessageFormat.format(query, param);
List<SWMessageR> records = (List<SWMessageR>) em.createNativeQuery(nativeQuery, SWMessageImpl.class)
.getResultList();
the above code produces the query like this:
db.SWMessages.aggregate([ { "$match" : { "messageUuid" : { "$ne" : "9c1464d7-311d-4b50-8b81-005bad055232" } } } , { "$group" : { "_id" : "$localReference", "max" : { "$max" : "$creationDate" } } } ])
My question is that the result of this query would return back an entity object which is the SWMessageR?

Well, yes the way you execute your query it will return a List Object of your class. In this way you don't need to use casting, so you can use it like this:
List<SWMessageR> records = em.createNativeQuery(nativeQuery, SWMessageImpl.class).getResultList();
Though, in case you are expecting a single result, I would suggest to use this way:
SWMessageR record = (SWMessageR) em.createNativeQuery( query1, SWMessageR.class ).getSingleResult();
Have a look at the Hibernate Search Documentation Query Section and everything will be clear.
Cheers.

Hibernate OGM can convert the result into an entity: https://docs.jboss.org/hibernate/stable/ogm/reference/en-US/html_single/#ogm-mongodb-queries-native
I'm not sure what your query returns, but if it's a document in the collection that represents your entity, I expect it to work.
You can see an example in our code base:
https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/test/java/org/hibernate/ogm/datastore/mongodb/test/query/nativequery/MongoDBSessionCLIQueryTest.java#L111
Make sure to pass the expected Entity type, it will look something like this:
List<SWMessageR> results = em
.createNativeQuery( nativeQuery, SWMessageR.class )
.getResultList();
Assuming that SWMessageR is the entity class.

Related

Returning IDs list of entities with specified value without defined entity/POJO

I am trying to write a method that returns me IDs (as a List ) of all records from a collection that have a certain status.
I am looking for a solution, but unfortunately I cannot find anything correct.
I currently have something like this:
List<String> getAllLecturersIdList() {
MongoCollection<Document> collection.mongoTemplate.getCollection("lecturers");
MongoCursor<Document> cursor = collection.find().iterator();
ArrayList<String> listOfIDS = new ArrayList<>();
while (cursor.hasNext()) {
listOfIDS.add(cursor.next().getObjectId("_id").toString());
}
return listOfIDS;
}
This method returns me a list of IDs of all lecturers.
The lecturer entity also has a "status" field with values like ACTIVE, LEAVE, FIRED and so on.
I would like to have only IDs of lecturers who have ACTIVE status to be returned to me.
How to do it to have only entities with ACTIVE status when returning from the collection, and not to clean the repository / services level?
Thanks for help in advance!
Important - I don't want an entity structure to be created in the application.
Therefore, the solution cannot contain a POJO / Entity Class and here is the problem (I cannot use e.g. Criteria, because every example is with defined entity )
You can fallback to the low level MongoOperations#executeQuery method if there is no result type mapping your query results:
List<String> getAllLecturersIdList() {
Query query = new Query();
query.fields().include("_id");
query.addCriteria(Criteria.where("status").is("ACTIVE"));
ArrayList<String> listOfIDS = new ArrayList<>();
mongoTemplate.executeQuery(query, "lecturers", document -> listOfIDS.add(document.getObjectId("_id").toString()));
return listOfIDS;
}
The following should work:
List<String> getAllLecturersIdList() {
MongoCollection<Document> collection.mongoTemplate.getCollection("lecturers");
MongoCursor<Document> cursor = collection.find().iterator();
ArrayList<String> listOfIDS = new ArrayList<>();
while (cursor.hasNext()) {
Document document = cursor.next();
if (document.getString("status") == "ACTIVE") {
listOfIDS.add(document.getObjectId("_id").toString());
}
}
return listOfIDS;
}

Jooq dsl one to many relations

I'm using Spring Data + Jooq DSL. As result entity I'm using not jooq generated entity, but simple one, without any annotations and for relations One To Many getting result:
[{
"id":2,
"name":"James",
"addresses":[
{
"id":null,
"country":null,
"street":null
}
]
}]
Is any way to return an empty array for addresses?
My code to perform a request:
public Set<User> getUserById(Set<Long> id) {
Set<User> result = new HashSet<>();
ResultQuery users = dsl.select(
field("u.id", Long.class).as("id"),
field("u.name", String.class).as("name"),
field("a.id", Long.class).as("addresses_id"),
field("a.country", String.class).as("addresses_country"),
field("a.street", String.class).as("addresses_street")
).from("schema.user_table u")
.leftJoin("schema.address_table a")
.on("u.id = a.user_id")
.where(field("u.id").in(id));
try(ResultSet rs = users.fetchResultSet()) {
JdbcMapper<User> mapper = JdbcMapperFactory
.newInstance()
.addKeys("id")
.newMapper(User.class);
result = mapper.stream(rs).collect(Collectors.toSet());
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Why not just use SQL/JSON to produce JSON documents directly from within your database?
public String getUserById(Set<Long> id) {
return dsl.select(coalesce(jsonArrayAgg(
jsonObject(
key("id").value(field("u.id", Long.class)),
key("name").value(field("u.name", String.class)),
key("addresses").value(coalesce(
jsonArrayAgg(jsonObject(
key("id").value(field("a.id", Long.class)),
key("country").value(field("a.country", String.class)),
key("street").value(field("a.street", String.class))
)),
jsonArray()
))
),
jsonArray()
)))
.from("schema.user_table u")
.leftJoin("schema.address_table a")
.on("u.id = a.user_id")
.where(field("u.id").in(id))
.fetchSingle().value1().data();
}
If you really need the intermediate User representation, then you can either:
Use Jackson or Gson to map the JSON document to the nested User DTO structure using reflection (works with jOOQ 3.14)
Use jOOQ 3.15's new MULTISET value constructor operator or MULTISET_AGG aggregate function along with ad-hoc converters, see below:
public Set<User> getUserById(Set<Long> id) {
return dsl.select(
field("u.id", Long.class),
field("u.name", String.class),
multisetAgg(
field("a.id", Long.class),
field("a.country", String.class),
field("a.street", String.class)
).convertFrom(r -> r == null
? Collections.<Address>emptyList()
: r.map(Records.mapping(Address::new)))
)
.from("schema.user_table u")
.leftJoin("schema.address_table a")
.on("u.id = a.user_id")
.where(field("u.id").in(id))
.fetchSet(Records.mapping(User::new));
}
Side note on code generation and execution
While not strictly relevant to this question, unless your schema is dynamic (not known at compile time), I really urge you to reconsider using source code generation. If you're not using it, you're missing out on a lot of jOOQ API advantages, just like when you're executing a jOOQ query with something other than jOOQ.
For me worked specify as a key addressId:
.addKeys("id", "addresses_id")

Reverse Regex Selection with Spring MongoDB

I have a mongo collection with objects like these:
[
{
"_id" : "a2d",
"entityType" : "Location",
"type" : "STRING",
},
{
"_id" : "a1_order",
"entityType" : "Order",
"type" : "STRING",
}
]
Trying to append the _entityType to all document's id where it is not present at the end id the id (the first object in the above case).
Using mongo with Spring, but I'm already stuck with the first step, to get all the objects with no entityType in id.
Thinking about something like this, with regex, but I'm not sure how should it look like:
Query query = new Query();
query.addCriteria( Criteria.where( "id" ).regex( "here i need the entity type of the current document" ) );
You can build your regex by '^' ('starts with' Regex).
So you need a function who point in all documents and check this filter
List<Document> result = new ArrayList<Document>();
StringBuilder idPrefix = new StringBuilder();
idPrefix.append("^");
idPrefix.append(idCode);
idPrefix.append("_");
List<Bson> filters = new ArrayList<Bson>();
filters.add(Filters.regex("_id", keyPrefix.toString()));
for (Document d : yourCollections.find(Filters.and(filters)))
list.add(d);
You actually want a "reverse regex" here, as you need to use the data in the document in order to match on another field.
Presently you can really only do this with MongoDB using $where, which evaluates JavaScript on the server. So for spring mongo, you need the BasicQuery instead, so we can construct from BasicDBObject and Code primatives:
BasicDBObject basicDBObject = new BasicDBObject("$where",
new Code("!RegExp('_' + this.entityType + '$','i').test(this.id)"));
BasicQuery query = new BasicQuery(basicDBObject);
That will test the "id" field in the document to see if it matches the value from entityType at the "end of the string" and without considering "case". The ! is a Not condition, so the "reverse" of the logic is applied to "not match" where the field actually did end that way.

Generated ObjectId for MongoDB

I'd need to generate ObjectId for my entities before I save them to MongoDB. I generate it simply with new org.bson.types.ObjectId(). It creates an object _id which is a quaternion of _time, _machine, _inc and _new. The value of _id itself looks like a normal MongoDB _id. Nevertheless after transforming to JSON and sending it to database, it's saved as an array of four elements. Is there any way how to make it to look like ObjectId generated by MongoDB - "_id" : ObjectId("54edaa41ca190ebda00a2abd") without any text preoprocessing?
This simple Java program works.
MongoClient mongoClient = new MongoClient();
ObjectId objectId = ObjectId.get();
DB test1 = mongoClient.getDB("test1");
BasicDBObject dbObject = new BasicDBObject("_id",objectId)
.append("key", "value");
test1.getCollection("test").insert(dbObject);
Now query with Shell, ObjectId is saved correctly.
> use test1
switched to db test1
> db.test.find()
{ "_id" : ObjectId("55520a15b8a0e51f45921946"), "key" : "value" }

How to represent the following query(mongodb) in java

I have a JSON in MongoDB with the following structure:
{
id:"_234234",
"stationId":"ALM",
"storageData": {
}
}
To retrieve JSON with storageData equal to null, in MongoDB I query as:
db.collection.find({"storageData":{"$gt" : {}}})
It gives me list of JSON bodies with empty storageData. So how do I represent that in Java
BasicDBObject obj=new BasicDDBObject("storageData", new BasicDBObject("$gt",{}));
collection.find(obj);
I am getting an error near BasicDBObject("$gt",{}))...
How do I represent ("$gt",{}) in Java??
First understand that null is a valid value. This would be valid:
{
id:"_234234",
StationId:"ALM",
StorageData: null
}
and retrieving the document, asking for storagedata which is null would retrieve the doc with the id _234234.
If what you need is to check which documents DON'T have the key "storagedata" then use the $exist keyword or construct the query in this way:
db.yourcollection.find("this.storagedata == null")
I would do it via query, and not in Java because it would alleviate cpu time and memory.
All you want to to here is represent an empty object:
BasicDBObject query = new BasicDBObject(
"storageData", new BasicDBObject(
"$gt",new BasicDBObject()
)
);
Which of course produces the query:
{ "storageData" : { "$gt" : { } } }
So that's it, just call BasicDBObject without any arguments.

Categories

Resources