Spring Data save date and time in specific format - mongodb

I don't understand how can I save date and time for example "eventDateFrom" in MongoDB in specific format.
I try do it like that:
Part of Event class:
public class Event {
#Id
private String id;
private String eventTitle;
#DateTimeFormat(pattern = "MM/dd/yyyy HH:mm:ss")
private Date eventDateFrom;
private String eventDateTo;
private Integer minEventPartcipants;
private String eventDateConfirmTo;
private String location;
private String minEventTime;
private List<Participant> participantList = new ArrayList<>();
Part of RunAtStart class:
Event event = new Event();
event.setEventTitle("Wyjazd na rower Turbacz");
event.setEventDateFrom(new Date("05/27/2017 10:00:00"));
event.setEventDateTo("27.05.2017 22:00:00");
event.setMinEventPartcipants(2);
event.setEventDateConfirmTo("26.05.2017 10:00:00");
event.setLocation("Lindego 13a");
event.setMinEventTime("06:00:00");
But the time "eventDateFrom" is wrong.
MongoDB document:
{
"_id" : ObjectId("592d34dcc5f2fd2d204d7db4"),
"_class" : "info.wzielezicki.app.MeetHelp.model.Event",
"eventTitle" : "Wyjazd na rower Turbacz",
"eventDateFrom" : ISODate("2017-05-27T08:00:00.000Z"),
"eventDateTo" : "27.05.2017 22:00:00",
"minEventPartcipants" : 2,
"eventDateConfirmTo" : "26.05.2017 10:00:00",
"location" : "Lindego 13a",
"minEventTime" : "06:00:00",
"participantList" : []
}
What I'm doing wrong?
Is the better way to define date and time format?

If you want to store a Date in a specific format and not the one, the store uses, you don't really want to store a Date, but a String, so just make the property of type String. You can still have additional accessors that use Date to use inside your application.

Related

#Id of type date for SpringData Mongo

The data pojo for spring-data-mongodb is configured as follows:
#Document(collection="DateKey")
public class DateKey {
#Id
private Date dateid;
private Date dateval;
private String firstName;
private String lastName;
The #Id column is a java.util.Date field, when the data is saved in mongo-db using spring-data-mongodb, it is getting saved as
{
"_id" : ObjectId("5a356628d73a971c3c8ab1e7")
}
Whenever other datatypes are used, no such behavior is observed. Due to this when we try to find the value from database, it throws the following exception
Caused by: org.springframework.core.convert.ConverterNotFoundException: No
converter found capable of converting from type [org.bson.types.ObjectId] to
type [java.util.Date]
only java.sql.Date is saved as Date in MongoDB, an ordinary java.util.Date is not!
Must provide a custom converter

How to get a maximum date among the list of past dates in drools?

From the List of Orders, i need to collect dates which are past to requesteffDate and requesteffTime and take the maximum of the past dates.
function boolean dateCheck(Date effdt, Date efftm) {
String efffdt = new SimpleDateFormat("yyyyMMdd").format(effdt);
String effftm = new SimpleDateFormat("HHmm").format(efftm);
Date effdttm = new SimpleDateFormat("yyyyMMddHHmm").parse(efffdt + "" + effftm);
return effdttm.before(new Date());
}
rule "finding past maximum date"
when
$company : Company( $date:requesteffDate, $time:requesteffTime, $reqdt : requesteffDate.getTime(), $reqtm : requesteffTime.getTime() )
eval(dateCheck($date,$time))
accumulate(Orders( effectiveDate != null,
effdate:effectiveDate.getTime()<$reqdt),
maxEffDate:max(effdate))
then
//error
While doing this,
accumulate(Orders(effectiveDate!=null,
effdate:effectiveDate.getTime()<$reqdt),
maxEffDate:max(effdate))
I am getting maxEffDate as -9223372036854775808 which when converted is showing 1940
Same I have tried using min functionn it is showing 2262.
My class goes like this.
Class Company{
private Date requesteffDate;
private Date requesteffTime;
private Employee emp;
private List<Orders> orderlist;
}
Class Orders{
private Date effectiveDate;
private Date effectiveTime;
}
-9223372036854775808 is Long.MIN_VALUE. This is conclusive for indicating that the accumulate doesn't find any Orders.
Make sure that you insert some matching Orders facts.
Add a guard that the maxEffDate is != Long.MIN_VALUE.
Discontinue the usage of Date as a time-of-day value: Either use LocalDate and LocalTime or combine date and time into a single Date value.
Take care that conversions of date and time are not affected by your locale settings.

MongoDb lte/ lt query behaving unexpectedly

I have connected to mongoDb using Spring. While creating query using Criteria, lt/ lte are not behaving the way they should i.e they are giving random outputs.
I want to Find a store within "x" miles of a zipcode
Query Creation/ execution code:
System.out.println("Please Enter your zipCode");
String zipCode = br.readLine();
System.out.println("Enter the distance (miles) to find store");
Integer distance = br.read();
Query query = new Query();
query.addCriteria(Criteria.where("storeDistance").lt(distance).and("storezipCode").is(zipCode));
List<Store>storeList = mongoOperation.find(query, Store.class);
if(storeList.isEmpty()){
System.out.println("Oops...no store found nearby...!!");
}else{
for(int idx=0; idx<storeList.size(); idx++){
System.out.println(storeList.get(idx).storeIdentificationumber+"\t"+storeList.get(idx).storeDistance);
}
}
Store model class
package com.storeApp.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection= "stores")
public class Store {
#Id
public String storeIdentificationumber;
public String storeName;
public String storezipCode;
public String storeCity;
public Integer storeDistance;
public Store(){}
public Store(String id, String name, String city, String zipCode, Integer distance){
this.storeIdentificationumber = id;
this.storeName = name;
this.storezipCode = zipCode;
this.storeCity = city;
this.storeDistance = distance;
}
}
Entries in Database :
{
"_id" : "store1",
"storeName" : "store One",
"storezipCode" : "123",
"storeCity" : "city",
"storeDistance" : 51
}
{
"_id" : "store03",
"storeName" : "Store Three",
"storezipCode" : "123",
"storeCity" : "city",
"storeDistance" : 54
}
Input :
Welcome to Store Application....!!
Please select choice from menu below
1. Add a Store
2. Find a Store
3. Remove a Store
2
Please Enter your zipCode
123
Enter the distance (miles) to find store
50
Expected Output :
Oops...no store found nearby...!!
Actual Output :
store1 51
According to the criteria and database, there should be no store whose distance is less than 50 miles, but still one record is being returned.
Issue is with Integer distance = br.read(); Assuming br is instance of BufferedReader. read method just reads a single character and gives the integer value of that character. You can verify by printing the distance variable.
You need to use readLine and convert the String number using Integer.parseInt
Yeah It's little weird, thing is if you want to add multiple options in your query, you should keep adding Criteria, One Criteria cannot take multiple fields.
In your case storezipCode is removing storeDistance from the Criteria chief field.
Try this
Query query = new Query();
query.addCriteria(Criteria.where("storeDistance").lt(distance));
query.addCriteria(Criteria.where("storezipCode").is(zipCode));
So question is in what scenario you would use 'and', You need to lookout for examples but it doesn't work the way we want it to work.

Find Results within Date range Using Mongo NamedQuery

I want to find the Results based on Mongo NamedQuery
#Document(collection="test")
#Getter
#Setter
public class TestData {
#Id
private String name;
private String fiscalWeek;
private String fiscalYear;
}
Here fisaclWeek in the range of 1 to 52
#Query("'fiscalWeek' : {$gt : ?0, $lt : ?1}}")
List<TestData> findByDateRange(String fromDate, String toDate);
here fromDate and toDate will come like this 512015 that means concatenation of week and year
I tried like the above way but need to concatenate fisaclWeek and fisaclYear but not sure how to concatenate in the #Query method
How to write a Query here so that I will get results in the range of fromDate and toDate?
Can anyone help on this.

spring data - Mongodb - findBy Method for nested objects

I have two domain objects,
#Document
public class PracticeQuestion {
private int userId;
private List<Question> questions;
// Getters and setters
}
#Document
public class Question {
private int questionID;
private String type;
// Getters and setters
}
My JSON doc is like this,
{
"_id" : ObjectId("506d9c0ce4b005cb478c2e97"),
"userId" : 1,
"questions" : [
{
"questionID" : 1,
"type" : "optional"
},
{
"questionID" : 3,
"type" : "mandatory"
}
]
}
I have to update the "type" based on userId and questionId, so I have written a findBy query method inside the custom Repository interface,
public interface CustomRepository extends MongoRepository<PracticeQuestion, String> {
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId,int questionID);
}
My problem is when I execute this method with userId as 1 and questionID as 3, it returns the entire questions list irrespective of the questionID. Is the query method name valid or how should I write the query for nested objects.
Thanks for any suggestion.
Just use the #Query annotation on that method.
public interface CustomRepository extends MongoRepository<PracticeQuestion, String> {
#Query(value = "{ 'userId' : ?0, 'questions.questionID' : ?1 }", fields = "{ 'questions.questionID' : 1 }")
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId, int questionID);
}
By adding the fields part of the #Query annotation, you are telling Mongo to only return that part of the document. Beware though, it still returns the entire document in the same format - just missing everything you did not specify. So your code will still have to return List<PracticeQuestion> and you will have to do:
foreach (PracticeQuestion pq : practiceQuestions) {
Question q = pq.getQuestions().get(0); // This should be your question.
}
Property expressions
Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties. Assume Persons have Addresses with ZipCodes. In that case a method name of List<Person> findByAddressZipCode(ZipCode zipCode);
creates the property traversal x.address.zipCode. The resolution algorithm starts with interpreting the entire part (AddressZipCode) as the property and checks the domain class for a property with that name (uncapitalized). If the algorithm succeeds it uses that property. If not, the algorithm splits up the source at the camel case parts from the right side into a head and a tail and tries to find the corresponding property, in our example, AddressZip and Code. If the algorithm finds a property with that head it takes the tail and continue building the tree down from there, splitting the tail up in the way just described. If the first split does not match, the algorithm move the split point to the left (Address, ZipCode) and continues.
Although this should work for most cases, it is possible for the algorithm to select the wrong property. Suppose the Person class has an addressZip property as well. The algorithm would match in the first split round already and essentially choose the wrong property and finally fail (as the type of addressZip probably has no code property). To resolve this ambiguity you can use _ inside your method name to manually define traversal points. So our method name would end up like so:
UserDataRepository:
List<UserData> findByAddress_ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);
ProfileRepository:
Profile findByProfileId(String profileId);
UserDataRepositoryImpl:
UserData userData = userDateRepository.findByUserId(userId);
Profile profile = profileRepository.findByProfileId(userData.getProfileId());
userData.setProfile(profile);
Sample Pojo :
public class UserData {
private String userId;
private String status;
private Address address;
private String profileId;
//New Property
private Profile profile;
//TODO:setter & getter
}
public class Profile {
private String email;
private String profileId;
}
For the above Document/POJO in your Repository Class:
UserData findByProfile_Email(String email);
For ref : http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
You need to use Mongo Aggregation framework :
1) Create custom method for mongo repository : Add custom method to Repository
UnwindOperation unwind = Aggregation.unwind("questions");
MatchOperation match = Aggregation.match(Criteria.where("userId").is(userId).and("questions.questionId").is(questionID));
Aggregation aggregation = Aggregation.newAggregation(unwind,match);
AggregationResults<PracticeQuestionUnwind> results = mongoOperations.aggregate(aggregation, "PracticeQuestion",
PracticeQuestionUnwind.class);
return results.getMappedResults();
2) You need to cretae a class(Because unwind operation has changed the class structure) like below :
public class PracticeQuestionUnwind {
private String userId;
private Question questions;
This will give you only those result which matches the provide userId and questionId
Result for userId: 1 and questionId : 111 :
{
"userId": "1",
"questions": {
"questionId": "111",
"type": "optional"
}
}
i too had similar issue. for that i added $ before the nested class attributes.
try below query
#Query(value = "{ 'userId' : ?0, 'questions.$questionID' : ?1 }") List<PracticeQuestion> findPracticeQuestionByUserIdAndQuestionsQuestionID(int userId, int questionID);