does morphia supports automatic timestamp? - mongodb

Does anyone knows if morphia supports automatic timestamp for create/update of documents in a collection in mongodb during its create/modify operations.
I have already come to know that this support is not available in mongodb. I would like to know if there is any way to get the last access/update time of data or documents in morphia driver.
Thanks,
sadish

I'm generally using a base entity, which all other entities extend. It provides the ObjectId, creation date, last change date, a disabled flag,...
The relevant code snippets look like this:
protected Date creationDate;
protected Date lastChange;
// Getters and setters or final setters which don't do anything,
// if you only want to allow the entity to update the values
#PrePersist
public void prePersist() {
creationDate = (creationDate == null) ? new Date() : creationDate;
lastChange = (lastChange == null) ? creationDate : new Date();
}

Sorry in advance if this isn't the exact answer you're looking for. But the short answer is no.
There appears to be no API in the latest Morphia which supports that operation. Maybe there is a bug opened to support this. In the meantime, you should use your favorite constructor for java.util.Date or java.sql.Timestamp.
The source code for Morphia has the appropriate converter built in to handle this TimestampConverter.java.
Only tangentially related. If your reason for using $currentDate is to avoid clock skew problems among multiple hosts, then you're barking up the wrong tree. Though not explicitly stated in the $currentDate documentation, it is documented that MongoDB does nothing to address clock skew among various hosts. This can be found in the documentation for ObjectId.getTimestamp(). Therefore, the usage of $currentDate is going to provide little benefit as opposed to time-stamping in the client side.

Related

Custom operator support in naming convention

as we know, spring-data-jpa supports repositories that generate queries based on function names, i.e (kotlin):
#Repository
interface LocationRepository : JpaRepository<DbLocation, UUID>,
JpaSpecificationExecutor<DbLocation>{
fun findOneByNameIgnoringCase(name: String)
}
Now, postgres supports some custom operators, for example timerange '#>' timestamp (read: timerange contains timestamp).
I'd like to have a function like this, without resorting to native queries/specifications:
#Repository
interface LocationRepository : JpaRepository<DbLocation, UUID>,
JpaSpecificationExecutor<DbLocation>{
fun findOneBySomeFieldContainsTimestamp(something: Instant)
}
Is there any way to extend spring data jpa to also support new operators?
Thanks in advance.
Is there any way to extend Spring Data JPA to also support new operators?
Not really.
Of course, technically the answer is yes since Spring Data is Open Source and you can fork it. A good starting point would be JpaQueryCreator.build() which contains a switch statement for all the supported operators.

MongoDB : Use string instead of BsonObjectId

I have a REST service for my game and decided to give MongoDB a try - seems pretty straight forward except for the "_id" field requirement.
The problem here is that my client app is using the REST services and has no knowledge of "mongodb", its drivers or dependencies - nor should it. To decouple the client from the server side (REST service provider) I need to get around the fact that MongoDB appears to require a "_id" field of type BsonObjectId.
Currently I'm using a lightweight DAO layer, so instead of having:
using System;
public class Item {
private BsonObjectId _id;
private string name;
}
I am using a DAO to translate this to something "mongodb agnostic":
using System;
public class ItemDAO {
private string _id;
private string name;
}
Ideally it would be nice to be rid of BsonObjectId entirely - is there some annotation/custom serialization handler that can be used or some way that I'm able to use a string instead of BsonObjectId?
Failing that, any way to get objects wrapped by MongoDB so they are decorated with the _id which I can inject back into the row as a string?
The ideal result would be to have no DAO class at all just "Item" and have Item using a string for _id (or something that does not require mongodb dependencies to bleed into client implementation).
Your documents must have an _id field, but it doesn't have to be an ObjectID. The only requirement is that it is unique for the collection.
MongoDB will generate an ObjectId for you if you don't supply an _id field when saving a new document, but that is just a helper function.
If you don't want to "polute" your model clases, you could register appropriate Id generator in you data access code.
BsonSerializer.RegisterIdGenerator(typeof(string), new StringObjectIdGenerator());
This way you will have String field in your model, but underneath it will be ObjectId, which is kind of nice i.e. you can see when the records where added (approx)
If you decide however that in your REST service you will accept Ids from clients (via PUT) then ObjectId is obviously not the way to go.
Have a look at this article since it describes how to setup serialization options etc.
How do you query for the objects? If you don't want / need the _id field in the client, you can use a projection to exclude the _id field from the result.
Also, be aware that generating your own string-based _id's can have severe impact on database size. The ObjectId seems to be a pretty efficient structure. I have experimented with using strings for _id, to avoid having an index on a field I would never use - but in my case the cost in database size made it unfeasible. Depends on your database size and the rest of the contents, of course.
It's commonplace to represent BSON ObjectIds as strings; by default, Mongo drivers will generate 96-bit IDs, which you can then obviously represent as 24 hex bytes. Most client libraries have facilities for creating ObjectIds out of strings and casting them to strings.
You would have your external interfaces treat _id as a string, and then when your Mongo-aware DB layer receives an _id as a string, it would just internally convert it with ObjectId.from_string(_id) or whatnot. When writing results, you would just cast the OID to a string.
Using ObjectIds as data type for your primary keys makes a lot of sense for various reasons. Generating good, non-sequential, monotonic IDs with low collision probability isn't trivial, and re-inventing the wheel or essentially rewriting the feature isn't worth the trouble.
Data mapping should be done in controllers, and they should interact with the outside using DTOs. In other words, your REST Endpoints (Controllers/Modules) should known DTOs while your database uses your database models.
The DTOs will look very similar to your models, but they might have a few less fields (neat if there's internal data you don't want exposed via the API) and they use strings where the models use ObjectIds.
To avoid stupid copying code, use something like AutoMapper.

How to use the exists keyword in Spring Data to check for the existence of an entity?

How do I use the 'exists' keyword in Spring Data in a query method?
I would like to have a method like this:
public interface ProfileRepository extends JpaRepository<Profile, Long> {
boolean existsByAttribute(String attribute);
}
where Attribute is a field of the Profile.
A workaround would be to use a custom-implementation. But the appendix defines exists as keyword. Could someone give me an example how to use this keyword?
Documented keywords are intended to be used in combination with a property reference. Thus, the semantics of EXISTS in this case are that it checks whether the property exists. Note, that the part of the documentation is pulled it from Spring Data Commons and the keyword being listed there doesn't mean it's supported in Spring Data JPA (indicated in the first paragraph of the section you linked). Exists is not supported by Spring Data JPA as it only makes sense in MongoDB for example as there's a difference between a field not present entirely and the field available with a logically null value.
So what you're looking for seems to be around the (Is)Null keyword with the current limitation that it would return objects and you'd have to check the returned list for content. There's a ticket to add support for projections for derived query methods which you might wanna follow for further progress.

Converting datetime to a long timestamp in JPQL

I have an entity with two columns:
// time when the event happened (stored in UTC)
#Temporal(TemporalType.TIMESTAMP)
private Date eventTime;
// timezone offset in milliseconds
// so local millis are eventTime.getTime() + offset
#Basic
private int offset;
It appears that in JPQL queries I can't use something like WHERE eventTime + offset > :parameter. But is it possible to work around by casting eventTime to a long in some way? Of course, there is an option of using native queries...
EDIT:
It isn't supported in the standard and isn't mentioned in OpenJPA documentation, so probably not possible at the moment.
It may not be possible for you to modify the table, but can you possibly just add another column which is the computed timestamp with offset? Then just base all of your queries off of that? It will probably yield better performance, as well.
Another way I've solved problems like this is to create a SQL view and and create a different #Entity based on that view. I have done this when I need a lot of complex computations and don't want all of that complexity in the code itself. This is useful when you have other non-JPA based applications that want to get at the same information (such as a reporting engine). While this solution ends up using a SQL view, it allows your Java/JPA code to not have to deal with native queries.
What I've done in similar situations before is to declare the setters/getters private or protected and then have public #Transient getters to perform the desired calculation.
This solves all programmatic issues. For desired jpa sql you'll need to perform the appropriate calculation in the query.

Persisting timestamp field as Date or Long?

I need a consensus on the practice of persisting timestamps, specifically on the pros & cons of using java.util.Date compared to using long.
Scope of this discussion:
Performance
Querying Flexibility (e.g. date range)
Any hazards in coding and querying
Portability (e.g. migration to other DB)
About myself:
I consider myself to be a beginner in JPA, dabbling in it once in a while, not being able to apply it into production level projects until now. In my current project, I commit myself to use ObjectDB (embedded) through JPA calls.
The following class demonstrates 3 possible methods for persisting timestamps in JPA:
#Entity
public class Timestamps {
private java.sql.Timestamp ts1;
private #Temporal(TemporalType.TIMESTAMP) java.util.Date ts2;
private long ts3;
:
}
Regarding performance and memory consumption, ts3 is a bit more efficient.
ts3 may be less convenient to use than ts1 and ts2 (in ObjectDB Database Explorer, reports, etc.).
Basic queries such as retrieval by date range are supported for all the three, but extracting date and time parts (YEAR, MONTH, etc.) in queries is not supported for ts3.
All these forms are expected to be portable.
ts1 and ts2 are practically equivalent.
More details are provided in the ObjectDB manual.
In the documentation of java it looks like timestamp is closer related to java.util.date
http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/Timestamp.html
additionally if you care about the semantic of your code, a timestamp is a date.
You should be aware about java.sql.Timestamp's fact before using it:
There are some classes in the Java platform libraries that do extend an instantiable
class and add a value component. For example, java.sql.Timestamp
extends java.util.Date and adds a nanoseconds field. The equals implementation
for Timestamp does violate symmetry and can cause erratic behavior if
Timestamp and Date objects are used in the same collection or are otherwise intermixed.
The Timestamp class has a disclaimer cautioning programmers against
mixing dates and timestamps. While you won’t get into trouble as long as you
keep them separate, there’s nothing to prevent you from mixing them, and the
resulting errors can be hard to debug. This behavior of the Timestamp class was a
mistake and should not be emulated. (Bloch, Effective Java, 2nd Ed.)