I am having trouble figuring out if GCP Datastore supports querying nested properties of an entity.
My use case right now is like so:
Module
-> Application
Module
Application
#Entity
class Module {
Long id;
#Reference
Applicaiton application;
}
#Entity
class Application {
Long id;
String name;
}
I want to try query the module based on its nested Application name. I have tried providing the filter like so without success:
Query<? extends BaseEntity> query = Query.newEntityQueryBuilder()
.setKind("module")
.setFilter(PropertyFilter.eq("application.name", "UserApp"))
.build();
I'm using Springs GCP datastore abstraction through their DatastoreTemplate, but this doesn't seem related given that when I try run the GQL on the GCP console I get no results back either.
SELECT * FROM module WHERE application.name = "UserApp"
Thanks for taking the time to read through this. Any help with this is greatly appreciated!
It looks like you are using a Reference and not an embedded entity. The Application in module is really a key reference to an Application entity. Thus the values of application are not an indexed on the Module entity.
I am using spring-cloud-gcp-starter-data-firestore for accessing Google Cloud Firestore in my Java Spring application.
Currently, my entity looks like this:
public class Subscription {
public String userId;
public String companyId;
// other properties
}
However, I obtain the userId and companyId via a reactor.core.publisher.Mono in org.springframework.security.core.context.ReactiveSecurityContextHolder.
How can I persist both properties which are nested inside Monos without resorting to Mono#block?
I am now using Mono#zipWith to combine both Monos. Then I am creating the entity inside Mono#flatMap.
service.getCompanyId()
.zipWith(service.getUserId())
.flatMap(objects -> createEntity(objects.getT1(), objects.getT2()))
I suggest following the tutorial in the Google codelab.
Here you can find that Firestore can be in Datastore mode which makes the previous tutorial suitable for you.
I got database with several collections in micorservice, so there's controllers which works fine. But I need to collect statistics from servers, including database. There's a good query serverStats() which gives all the information about the server, but how can I pass it through app layers?
I made interface repository extended ReactiveCrudRepository using SomeModel class as a place holder and wrote one method like String getStatistics() with #Query annotation, but it doesn't work
public interface MongoMonitoring extends ReactiveCrudRepository<SomeModel, String> {
#Query("{ serverStatus: 1 }")
String getStatus();
Use MongoTemplate. The code like:
private MongoTemplate mongoTemplate;
Document result = this.mongoTemplate.executeCommand("{ serverStatus: 1 }");
The document is from package org.bson.Document which is like JSON.
I'm going to start a project of a REST application managed with Spring and with Hibernate for my model.
I know that Spring allows you to get Java object from the HTTP Request (with #Consumes(JSON) annotation). Is there any conflict if this Java object is also a Hibernate entities? And is nested object working (like #ManyToOne relation)?
Maven dependency
The first thing you need to do is to set up the following Hibernate Types Maven dependency in your project pom.xml configuration file:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Domain model
Now, if you are using PostgreSQL, you need to use the JsonType from Hibernate Types.
In order to use it in your entities, you will have to declare it on either class level or in a package-info.java package-level descriptor, like this:
#TypeDef(name = "json", typeClass = JsonType.class)
And, the entity mapping will look like this:
#Type(type = "json")
#Column(columnDefinition = "json")
private Location location;
If you're using Hibernate 5 or later, then the JSON type is registered automatically by the Postgre92Dialect.
Otherwise, you need to register it yourself:
public class PostgreSQLDialect extends PostgreSQL91Dialect {
public PostgreSQL92Dialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
}
The JsonType works with Oracle, SQL Server, PostgreSQL, MySQL, and H2 as well. Check out the project page for more details about how you can map JSON column types on various relational database systems.
Yes, this wouldn't be a problem and is actually a fairly common practice.
In the recent years I have come to realize that sometimes, however, it is not a good idea to always build your views based on your domain directly. You can take a look at this post:
http://codebetter.com/jpboodhoo/2007/09/27/screen-bound-dto-s/
It is also known as "Presentation Model":
http://martinfowler.com/eaaDev/PresentationModel.html
The idea behind that is basically the following:
Imagine you have the domain entry User, who looks like that :
#Entity
#Data
public class User {
#Id private UUID userId;
private String username;
#OneToMany private List<Permission> permissions;
}
Let's now imagine you have a view where you wanna display that user's name, and you totally don't care about the permissions. If you use your approach of immediately returning the User to the view, Hibernate will make an additional join from the Permissions table because event though the permissions are lazily loaded by default, there is no easy way to signal to the jackson serializer or whatever you are using, that you don't care about them in this particular occasion, so jackson will try to unproxy them (if your transaction is still alive by the time your object is put for json serialization, otherwise you get a nasty exception). Yes, you can add a #JsonIgnore annotation on the permissions field, but then if you need it in some other view, you are screwed.
That a very basic example, but you should get the idea that sometimes your domain model can't be immediately used to be returned to the presentation layer, due to both code maintainability and performance issues.
We were using such approach to simplify design and get rid of many dtos (we were abusing them too much). Basically, it worked for us.
However, in our REST model we were trying to do not expose other relations for an object as you can always create another REST resources to access them.
So we just put #JsonIgnore annotations to relations mappings like #OneToMany or #ManyToOnemaking them transient.
Another problem I see that if you still like to return these relations you would have to use Join.FETCH strategy for them or move transaction management higher so that transaction still exists when a response is serialized to JSON (Open Session In View Pattern).
On my opinion these two solutions are not so good.
You can map the json request without using any library at REST web-services (Jersy)
this sample of code:
This hibernate entity called book:
#Entity
#Table(name = "book", schema = "cashcall")
public class Book implements java.io.Serializable {
private int id;
private Author author; // another hibernate entity
private String bookName;
//setters and getters
}
This web-services function
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String addBook(Book book) {
String bookName=book.getName();
return bookName;
}
This is sample json request:
{
"bookName" : "Head First Java",
"author" : {
"id" : 1
}
}
Since you are just starting, perhaps you could use Spring Data REST?
This is the project: http://projects.spring.io/spring-data-rest/
And here are some simple examples:
https://github.com/spring-projects/spring-data-book/tree/master/rest
https://github.com/olivergierke/spring-restbucks
As you can see in the examples, there are no extra DTOs beyond the #Entity annotated POJOs.
I am using spring and the MongoTemplate and trying to write an equivalent query SQL LIKE statement.. I am have not seen a satisfactory answer, code below:
#Document
public class Lake {
#Id
private String oid;
#Indexed (sparse = true)
private String name;
private String state;
}
public List<Lake> listLakesLike(String likename) {
try {
Query filter = new Query(Criteria.where("name").regex("lakename","i"));
List<Lake> lakes = mongoTemplate.find(filter, Lake.class);
return lakes
}
I saw this as an example that DOES NOT work, no lakes returned.
How do I write a mongoTemplate.find that results in matching LIKE lake names based on the passed in value likename?
Thank you in advance.. This is driving me crazy.. Or if you can point me to an example.
Spring MongoDB syntax
Query filter = new Query(Criteria.where("name").regex("lakename","i"));
Is equivalent to MongoDB shell command
db.lake.find({name:/lakename/i})
Notice in spring leading and trailing slashes are not required. Try the command first in your shell to check you have all the data correct, if it doesn't work I'm pretty sure your problem lies elsewhere (eg: your Spring MongoDB is pointing to a wrong host / database.collection name)
Also notice Spring MongoDB implicitly converts the class name Lake into collection name lake (with lowercase). If you need to specify explicit collection name you can do so using #Document(collection = "Lake")