Best Practise for Handling Date in Spring Data MongoDb - spring-data-mongodb

I am running into few issues around handling dates in my project. This is what I have.
In My Entities, I am using ZonedDateTime.
private ZonedDateTime assignedOn;
Have Configured converters in Spring to handle this
public static class ZonedDateTimeToDateConverter implements Converter {
public static final ZonedDateTimeToDateConverter INSTANCE = new ZonedDateTimeToDateConverter();
private ZonedDateTimeToDateConverter() {}
#Override
public Date convert(ZonedDateTime source) {
return source == null ? null : Date.from(source.toInstant());
}
}
public static class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
public static final DateToZonedDateTimeConverter INSTANCE = new DateToZonedDateTimeConverter();
private DateToZonedDateTimeConverter() {}
#Override
public ZonedDateTime convert(Date source) {
return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
I see that data is stored in Mongodb as ISO date. This what i see in Mongodb.
"completed_on" : ISODate("2017-04-12T20:02:40.000+0000"),
My Question is related to querying these date fields using Spring. If I want to find all the records (equals operator) matching only the date part and not the time part, what should be the approach? I saw example in this thread
Spring data mongodb search for ISO date
Which suggest something like this.
query.addCriteria(Criteria.where("created").ne(null).andOperator(
Criteria.where("created").gte(DateUtils.getDate("2016-04-14 00:00:00", DateUtils.DB_FORMAT_DATETIME)),
Criteria.where("created").lte(DateUtils.getDate("2016-04-14 23:59:59", DateUtils.DB_FORMAT_DATETIME))
));
Just wanted to see if this is the only approach or there's another elegant way to do this?

Related

Retrieve Max value from a field using Spring Data and MongoDB

I want to obtain the maximum value of the field code within my User entity, using Spring Data and MongoDB.
I have seen similar examples using as below,
".find({}).sort({"updateTime" : -1}).limit(1)"
But have no idea how to integrate it into my own repository using the #Query annotation.
Any alternative solution, than to return the maximum value of said field is also welcome.
Thank you.
You can write a custom method for your repository.
For example you have:
public interface UserRepository extends MongoRepository<User, String>, UserRepositoryCustom {
...
}
Additional methods for repository:
public interface UserRepositoryCustom {
User maxUser();
}
And then implementation of it:
public class UserRepositoryImpl implements UserRepositoryCustom {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public User maxUser() {
final Query query = new Query()
.limit(1)
.with(new Sort(Sort.Direction.DESC, "updateTime"));
return mongoTemplate.findOne(query, User.class)
}
}
You can use the spring data method syntax like:
public User findTopByOrderByUpdateTimeAsc()
A reference can be found here: https://www.baeldung.com/jpa-limit-query-results#1first-ortop
Use this code in spring to get the latest updated time from mongodb: (mongoTemplate)
public List getTopPosts() {
Query query = new Query();
query.with(Sort.by(Sort.Direction.DESC, "postUploadedTime"));
return mongoTemplate.find(query,Post.class);
}

Spring + Hibernate + MS SQL server - UTC time zone

I have developed simple application with Spring 4.2.5 + Hibernate 5.1.0 - database system is MS SQL Server 2014.
From few days I am struggling with correct storing time + timezone in database.
Requirements that I need to fulfill is:
Save all dates in UTC time zone.
Store timezone in database column value.
To achieve it I created model called MyComment:
#Entity
#Table(name = "MY_COMMENT")
#EntityListeners(value = { MyCommentListener.class })
#Audited
public class MyComment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Column(name = "DATE_", nullable = false)
private Timestamp date;
...
}
To enforce saving dates in UTC time zone I used Jadira framework:
hibProperties.put("jadira.usertype.autoRegisterUserTypes", true);
hibProperties.put("jadira.usertype.javaZone", "UTC");
hibProperties.put("jadira.usertype.databaseZone", "UTC");
However during each create/update operation of MyComment object, MyCommentListener is getting date from my local timezone (not UTC date!):
public class MyCommentListener {
#PreUpdate
#PrePersist
public void setLastUpdate(MyComment myComment) {
myComment.setDate(new Timestamp(System.currentTimeMillis()));
}
}
Do you know how can I solve this issue?
Should I use other date type in my model? Different than Timestamp?
What kind of type should be DATE_ column in MS SQL server database?
I will appreciate any help. Thank you.
AFAIK, the problem is with listener. Replace the following code in listener and verify. Change the date format as per your need.
#PreUpdate
#PrePersist
public void setLastUpdate(MyComment myComment) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
myComment.setDate(dateFormat.getCalendar().getTime());
}
You can set a timezone property in the application properties file as below.
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
It was very strange for me that there's no property in Spring to set up default TimeZone - at least I do not know about it.
After some googling I found out that the best place in Spring to set time zone is WebApplicationInitializer, so I prepared following code:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
setupTimeZone();
}
private void setupTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}

How to use dynamic schema in spring data with mongodb?

Mongodb is a no-schema document database, but in spring data, it's necessary to define entity class and repository class, like following:
Entity class:
#Document(collection = "users")
public class User implements UserDetails {
#Id private String userId;
#NotNull #Indexed(unique = true) private String username;
#NotNull private String password;
#NotNull private String name;
#NotNull private String email;
}
Repository class:
public interface UserRepository extends MongoRepository<User, String> {
User findByUsername(String username);
}
Is there anyway to use map not class in spring data mongodb so that the server can accept any dynamic JSON data then store it in BSON without any pre-class define?
First, a few insightful links about schemaless data:
what does “schemaless” even mean anyway?
“schemaless” doesn't mean “schemafree”
Second... one may wonder if Spring, or Java, is the right solution for your problem - why not a more dynamic tool, such a Ruby, Python or the Mongoshell?
That being said, let's focus on the technical issue.
If your goal is only to store random data, you could basically just define your own controller and use the MongoDB Java Driver directly.
If you really insist on having no predefined schema for your domain object class, use this:
#Document(collection = "users")
public class User implements UserDetails {
#Id
private String id;
private Map<String, Object> schemalessData;
// getters/setters omitted
}
Basically it gives you a container in which you can put whatever you want, but watch out for serialization/deserialization issues (this may become tricky if you had ObjectIds and DBRefs in your nested document). Also, updating data may become nasty if your data hierarchy becomes too complex.
Still, at some point, you'll realize your data indeed has a schema that can be pinpointed and put into well-defined POJOs.
Update
A late update since people still happen to read this post in 2020: the Jackson annotations JsonAnyGetter and JsonAnySetter let you hide the root of the schemaless-data container so your unknown fields can be sent as top-level fields in your payload. They will still be stored nested in your MongoDB document, but will appear as top-level fields when the ressource is requested through Spring.
#Document(collection = "users")
public class User implements UserDetails {
#Id
private String id;
// add all other expected fields (getters/setters omitted)
private String foo;
private String bar;
// a container for all unexpected fields
private Map<String, Object> schemalessData;
#JsonAnySetter
public void add(String key, Object value) {
if (null == schemalessData) {
schemalessData = new HashMap<>();
}
schemalessData.put(key, value);
}
#JsonAnyGetter
public Map<String, Object> get() {
return schemalessData;
}
// getters/setters omitted
}

Alternative to Using an Entity as a Parameter to an Invoke Method in WCF RIA Services

Howdy, ya'll! First question on StackOverflow! :-)
So here's the scenario: We're working on a web app with Silverlight 4 and using WCF RIA Services 1.0 SP1 Beta for the web service. I have my entities in the Entity Framework Designer, but I'm using a slightly-modified ADO.NET C# POCO Entity Generator template to generate the classes.
What I'd like to do is have a method inside a Domain Service with the following signature:
[EnableClientAccess]
public class ResultService : DomainService
{
[Invoke]
public SerializableResult CalculateResult(EntityOne e1, EntityTwo e2);
}
I am returning both EntityOne and EntityTwo to the client through queries in other services, like so:
[EnableClientAccess]
public class EntityOneService : DomainService
{
public IQueryable<EntityOne> GetEntityOnes();
}
[EnableClientAccess]
public class EntityOneService : DomainService
{
public IQueryable<EntityTwo> GetEntityTwos();
}
Those classes are successfully being generated in the Silverlight project. The SerializableResult does not have a key.
When I try to compile, I get the following error: "Operation named 'CalculateResult' does not conform to the required signature. Parameter types must be an entity or complex type, a collection of complex types, or one of the predefined serializable types."
In my research, the most helpful information I found were in the comments of this post by Jeff Handley.
Of note, Peter asked in a comment:
I get an 'does not conform to the required signature ...' compile error if my complex object has an [Key] Attribute. When I remove this attribute I can use the object as parameter for an Invoke operation.
Jeff's response:
This is by design. Complex objects cannot have Key properties. If you have a Key the class gets treated as an Entity.
So it sounds as if any further efforts to try to get my method to work will be futile. However, I was wondering if anyone else has come across this problem, and what they did to solve it.
Thanks very much!
I have the following and it works for me.
namespace BusinessApplication2.Web
{
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
[EnableClientAccess()]
public class DomainService1 : DomainService
{
public IQueryable<EntityOne> GetEntityOnes()
{
return null;
}
public IQueryable<EntityTwo> GetEntityTwos()
{
return null;
}
[Invoke]
public SerializableResult GetSerializableResult(EntityOne one, EntityTwo two)
{
return new SerializableResult() { Result = "It woooooorrrked!" };
}
}
public class EntityOne
{
[Key]
public int Id { get; set; }
}
public class EntityTwo
{
[Key]
public int Id { get; set; }
}
public class SerializableResult
{
public string Result { get; set; }
}
}
Many thanks to Mr. Jeff Handley and Mr. Dinesh Kulkarni for the answer (through Twitter).
In order for an Entity to be used as a parameter in an invoke method, that Entity must be exposed through a query method existing within the same DomainService. The intention for this restriction is that
"Each domain service needs to be able to stand on its own."
By adding two dummy Query methods (see Jeff's answer for an example), I was able to compile my code.

Inheritance concept in jpa

I created one table using Inheritance concept to sore data into google app engine datastore. It contained following coding but it shows error.How to user Inheritance concept.What error in my program
Program 1:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class calender {
#Id
private String EmailId;
#Basic
private String CalName;
#Basic
public void setEmailId(String emailId) {
EmailId = emailId;
}
public String getEmailId() {
return EmailId;
}
public void setCalName(String calName) {
CalName = calName;
}
public String getCalName() {
return CalName;
}
public calender(String EmailId, String CalName) {
this.EmailId = EmailId;
this.CalName = CalName;
}
}
Program 2:
#Entity
public class method extends calender {
#Id
private String method;
public void setMethod(String method) {
this.method = method;
}
public String getMethod() {
return method;
}
public method(String method) {
this.method = method;
}
}
My constraint is I want output like this
Calendartable contain
Emailid
calendarname
and method table contain
Emailid
method
How to achieve this?
It shows the following error in this line public method(String method)
java.lang.Error: Unresolved compilation problem:
Implicit super constructor calender() is undefined. Must explicitly invoke another constructor
According to Using JPA with App Engine, the JOINED inheritance strategy is not supported.
Your code doesn't compile, add a default constructor in Calendar.
I don't think you should annotate the method field with #Id.
The datastore of GAE/J is not an RDBMS so consequently the only "inheritance strategy" that makes any sense is TABLE_PER_CLASS. I would expect GAE/J to throw an exception if you specify that strategy, and if it doesn't then you ought to raise an issue against them
Your error "constructor calender() is undefined" is rather straightforward. You should create constructor without parameters in calendar class (you can make it private if you don't want to use it). That's because compiler can create default constructor by himself only if there aren't another constructors in the class.

Resources