How to update entity with Mongo server time
Query query = new Query(new Criteria("id").is(user.getId()));
Update update = new Update().set("text", text)
.set("timeStamp", ??? );
This field should only be updated in one method
#LastModifiedDate It does not suit me?
timeStamp is LocalDateTime
You want either .currentDate() or .currentTimestamp() depending on your intended storage result.
Update update = new Update().set("text", text)
.currentDate("timeStamp");
Which actually corresponds to the $currentDate BSON update modifier and all the same usage, being of { $type: "date" } or { $type: "timestamp" } in it's options for the respective methods.
These are BSON Date values and therefore UTC Time.
Get the idea of Local time out of your head, since it has no business being stored in a database which can be accessed around the world.
Related
I have an entity named A, which has a createdDate with this type #Temporal(TemporalType.TIMESTAMP).
I tried to retrieve all the rows having a certain createdDate. I attached a certain date to the request and I printed that date, it looks fine like "2021-02-11 12:14:02.425", which has all the values up to millisecond.
But the sql from hibernate, the value for createdDate in the where clause is set as '11-Feb-21'. Therefore, I do not find any rows because the createdDate is saved as 2021-02-11 12:14:02.425 in the db.
public Response getByCreatedDate(Request req) {
List<AResponse> aList = aRepository.findByIdAndCreatedDate(req.getId(), req.getCreatedDate());
}
I am new for Hibernate, I tried find some useful information about it but could not. Do I have to explicitly create a new Date with those specific date and time and send it to the method 'findByIdAndCreatedDate'? If anyone has the same experience, could you give some information about it?
So, as in the title, I have the following example Document in my MongoDB database:
{"_id":{"$oid":"5fcf541b466a3d10f55f8241"}, "dateOfBirth":"1992-11-02T12:05:17"}
As you can see, the date is stored as a String and not as an ISODate object. As far as I know, MongoDB should be able to still handle and query it as a Date. (source)
Thus, I am trying to query it in my java app with JDBC in the following way:
java.util.Date queryDate = new GregorianCalendar(1980, Calendar.JANUARY, 1).getTime();
Bson query = Filters.gte("dateOfBirth", queryDate);
FindIterable<Document> result = collection.find(query);
However, this does not work. My thought process was, if I pass in a java.util.Date, then the Filters.gte() method will know i mean to query a Date and it will work as intended in MongoDB. However, I get 0 matches.
I also tried putting a formatter on my queryDate (for a different purpose, before):
DateFormat dformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Bson query = Filters.gte("dateOfBirth", dformat.format(queryDate));
However, this caused the Filters.gte() to query it as Strings, according to String-Comparison, so alphabetical order roughly. This made me think initially that the original java.util.Date version did/should indeed know then, that I queried a Date and not a String, it just somehow failed to convert the one in the database to a date-type? I'm unsure how it should work.
I understand this is a niche case usage, and that I really should insert dates as ISODate in mongoDB, however in my special case right now, this is not an option.
Is there a way to query dates stored as Strings in MongoDB if I am using JDBC?
Minor point: You are using the Java connector for MongoDB. JDBC drivers are for relational databases which use the SQL query language. I therefore changed the JDBC tag to Java in your question.
Working with Dates as Strings
Regarding the datetime format in your documents: Because of the format you are using, and because it is stored as a string, it is OK to use string comparisons when running your queries. Lexical ordering will ensure your string comparisons will be equivalent to datetime comparisons. This is what is being used by the code in the question you linked to.
Obviously this assumption will break if you have any data stored in other string formats, such as "dd-MM-yyyy", where the string ordering would not match the datetime ordering.
However you proceed, you should avoid the old and problematic Java Date and Calendar classes. Instead, use the modern java.time classes. More background here.
In your case, your documents are storing datetime data without any timezone or offset information. You can use java.time.LocalDateTime for this. The word "local" in this name actually means "no specific locality or timezone" - which matches what you have in your Mongo documents.
The Java imports:
import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
And an example local datetime:
LocalDateTime ldt = LocalDateTime.of(1980, Month.JANUARY, 1, 0, 0);
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
String s = ldt.format(dtf); // "1980-01-01T00:00:00"
Working with Dates as Objects
If you want to use a Java LocalDate object directly in your query, instead of using string comparisons, you can use a projection to create a date object in your query results, and then use the Java LocalDate object directly in your filter:
Bson resultsWithDate = Aggregates.project(Projections.fields(
Projections.include("dateOfBirth"),
Projections.computed("birthDate", Projections.computed("$toDate", "$dateOfBirth"))
));
The above projection adds a new dateOfBirth field to each retrieved document, and populates it via the $toDate operator.
Then we can apply our filter:
collection.aggregate(
Arrays.asList(
resultsWithDate,
Aggregates.match(Filters.gte("birthDate", ldt)))
).forEach(printConsumer);
The filter now uses our ldt object, from above.
I am using the following helper method to print each results document as a JSON string in my console:
Consumer<Document> printConsumer = (final Document document) -> {
System.out.println(document.toJson());
};
There may be a more compact or efficient way to build this MongoDB aggregate - I am not a regular Mongo user.
Also, as a final note: My use of the Mongo $toDate operator does not specify a timezone - so it defaults to Zulu time (UT timezone), as shown in the sample output below:
{
"_id": {
"$oid": "5fcf541b466a3d10f55f8241"
},
"dateOfBirth": "1992-11-02T12:05:17",
"birthDate": {
"$date": "1992-11-02T12:05:17Z"
}
}
I have been given some code to work on. I need to modify the existing code to return an extra column. Using the tool, SQLDeveloper, I can see an example record (notice Date AND Time information is present):
30-NOV-17 15:54:00
The code that I have been given to work on does the following:
// Create a Hibernate query (Oracle SQL query)
Query query = session.createSQLQuery(<NATIVE_SQL_QUERY_HERE>);
List<Object[]> rawDataRows = query.list();
if (rawDataRows != null) {
for(Object[] rawDataRow : rawDataRows) {
// I am trying to get the Date AND Time here
Timestamp ts = (Timestamp) rawDataRow[7];
}
}
The problem is that I get an error when I try this approach (Cannot cast java.sql.Date to Timestamp).
When I access the data without the cast (just get the data in a Date object), I DO NOT get the Time information. And I need to have BOTH.
So far, nothing I have tried has worked - other posts have similar issues, but they are not quite the same.
Any advice/suggestions much appreciated - THANKS!
You can use this code:
....
Calendar calendar = Calendar.getInstance();
calendar.setTime(rawDataRow[7]);
Timestamp ts = new Timestamp(calendar.getTimeInMillis());
...
When I query MongoRepository via Date field with Criteria in a Spring Boot application, the result is wrong. Here is my method:
Query query = new Query(new Criteria().andOperator(
Criteria.where("id").is(filter.getId()),
Criteria.where("datas.ts").lt(filter.getEndTime()).gte(filter.getStartTime())
));
List<PhaseData> phaseDatas = mongoOperations.find(query, PhaseData.class);
List<Data> result = new ArrayList<Data>();
for(Data pData : phaseDatas) {
result.addAll(pData.getDatas());
}
return result;
When I query with
{
"id" : "1234",
"startTime" : "2016-08-04 12:00",
"endTime" : "2016-08-04 15:00"
}
it gives me records with hour 16:54 & 21:12 too. How can I solve this issue?
Not sure if this addresses your question directly.
The DB won't return wrong result to the query. So I think it could be one of the following things:
It could be that the when you view the documents in mongodb, it displays date in iso format. So view the documents in the same format as you are creating dates for your query.
It could be timezone issue.
Mongodb dates can be considered as ISODate (MongoDB Date)
When you query, you create date objects in your timezone. So as a first debugging measure, I would see if both my DB and query timezones are the same.
Also, probably it would help if you query by creating date objects in ISODate by using SimpleDateFormat(SDF is not thread safe).
I have found that it could be confusing because the dates that you send are in a different format and the documents that you visually see in mongodb tool are displaying dates in iso format. I think that it could be the issue. The results are good, but probably you are viewing the two things differently and it causes the confusion.
I have an action in struts2 that will query the database for an object and then copy it with a few changes. Then, it needs to retrieve the new objectID from the copy and create a file called objectID.txt.
Here is relevant the code:
Action Class:
ObjectVO objectVOcopy = objectService.searchObjects(objectId);
//Set the ID to 0 so a new row is added, instead of the current one being updated
objectVOcopy.setObjectId(0);
Date today = new Date();
Timestamp currentTime = new Timestamp(today.getTime());
objectVOcopy.setTimeStamp(currentTime);
//Add copy to database
objectService.addObject(objectVOcopy);
//Get the copy object's ID from the database
int newObjectId = objectService.findObjectId(currentTime);
File inboxFile = new File(parentDirectory.getParent()+"\\folder1\\folder2\\"+newObjectId+".txt");
ObjectDAO
//Retrieve identifying ID of copy object from database
List<ObjectVO> object = getHibernateTemplate().find("from ObjectVO where timeStamp = ?", currentTime);
return object.get(0).getObjectId();
The problem is that more often than not, the ObjectDAO search method will not return anything. When debugging I've noticed that the Timestamp currentTime passed to it is usually about 1-2ms off the value in the database. I have worked around this bug changing the hibernate query to search for objects with a timestamp within 3ms of the one passed, but I'm not sure where this discrepancy is coming from. I'm not recalculating the currentTime; I'm using the same one to retrieve from the database as I am to write to the database. I'm also worried that when I deploy this to another server the discrepancy might be greater. Other than the objectID, this is the only unique identifier so I need to use it to get the copy object.
Does anyone know why this is occuring and is there a better work around than just searching through a range? I'm using Microsoft SQL Server 2008 R2 btw.
Thanks.
Precision in SQL Server's DATETIME data type does not precisely match what you can generate in other languages. SQL Server rounds to the nearest 0.003 - this is why you can say:
DECLARE #d DATETIME = '20120821 23:59:59.997';
SELECT #d;
Result:
2012-08-21 23:59:59.997
Then try:
DECLARE #d DATETIME = '20120821 23:59:59.999';
SELECT #d;
Result:
2012-08-22 00:00:00.000
Since you are using SQL Server 2008 R2, you should make sure to use the DATETIME2 data type instead of DATETIME.
That said, #RedFilter makes a good point - why are you relying on the time stamp when you can use the generated ID instead?
This feels wrong.
Other than the objectID, this is the only unique identifier
Databases have the concept of a unique identifier for a reason. You should really use that to retrieve an instance of your object.
You can use the get method on the Hibernate session and take advantage of the session and second level caches as well.
With your approach you execute a query everytime you retrieve your object.