I got document that looks like this
#Document(collection="myDocument")
public class MyDocument {
#Id
private String id;
private List<Dates> dates;
}
public class Dates{
private String key;
private DateTime value;
}
And OtherDocument is container for DateTime values from various sources, I can't simply make fields like DateTime birthdate; inside MyDocument because I don't know what key will be, they are just some dates that describe MyDocument. Now, I need to create search engine for those values, for example, someone want's to find all MyDocuments with dates that contains:
key : "Birthdate" greater than
value : "1990-01-01 00:00:00 +00:00"
and key : "Mather's birthday" less than
value: "1975-01-01 00:00:00 +00:00"
So, Criteria (using MongoTemplate here) first may look like this
Criteria criteria = Criteria.where("myDocument.dates.value")
.exists(true)
.gt(DateTimeUtil.valueOf("1990-01-01 00:00:00 +00:00")) //just converting String to DateTime here
.and("myDocument.dates.name")
.exists(true)
.all("Birthday"));
And second one:
Criteria criteria = Criteria.where("myDocument.dates.value")
.exists(true)
.lt(DateTimeUtil.valueOf("1975-01-01 00:00:00 +00:00"))
.and("myDocument.dates.name")
.exists(true)
.all("Mather's birthday"));
The problem is, I can't put those both Criteria in one Query, it will cause error. The only soultion I found till now is to make 2 separate Query in that case and then find common part by using
resultA.retainAll(resultB)
But the point is, I don't want to, this database will store a lot of data and those requests will be very frequent. I need this to work fast, and combining 2 lists in pure Java will be slow as hell with that amount of data. Any ideas how to deal with that?
edit#
here is the error thrown when I try to combine 2 Criteria like this in one Query
caught: (java.lang.RuntimeException), msg(json can't serialize type :
class org.joda.time.DateTime) java.lang.RuntimeException: json can't
serialize type : class org.joda.time.DateTime
You can use below code. $and the query together and use $elemMatch to match the dates fields on multiple condition.
Something like
Criteria criteria1 = Criteria.where("dates").
elemMatch(
Criteria.where("value").exists(true).gt(DateTimeUtil.valueOf("1990-01-01 00:00:00 +00:00"))
.and("name").exists(true).all("Birthday")
);
Criteria criteria2 = Criteria.where("dates").
elemMatch(
Criteria.where("value").exists(true).lt(DateTimeUtil.valueOf("1975-01-01 00:00:00 +00:00"))
.and("name").exists(true).all("Mather's birthday")
);
Criteria criteria = new Criteria().andOperator(criteria1, criteria2);
Note: You may still have the problem with joda time conversion.
Related
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.
Before I start, I have already searched around for an answer to this issue and the best answer I could come up with is this question
I have one difference though. I have a table that maintains a history of many documents. Therefore I need to query on an ID as well as the date range. Here is what my query currently looks like in Java
BasicDBObject searchQuery = new BasicDBObject();
searchQuery.put("id", id);
searchQuery.put("dateModified", BasicDBObjectBuilder.start("$gte", fromDate).add("$lte", toDate).get());
DBCursor cursor = table.find(searchQuery);
This returns no results. The MongoQuery that is generated by this block of code looks like this:
db.history.find({ "id" : 12345 , "dateModified" : { "$gte" : { "$date" : "2015-01-19T00:00:00.000Z"} , "$lte" : { "$date" : "2015-01-25T00:00:00.000Z"}}});
When I manually type this into MongoDB command line, this also returns no results. I currently have one record in the database for testing purposes that looks like this:
{
"id" : NumberLong(12345),
"dateModified" : ISODate("2015-01-21T19:42:28.044Z")
}
This object should clearly match the query, yet nothing is returning, any ideas?
EDIT: So it turns out that the string generated by the query object doesn't match the ISODate object in the database. I'd like to clarify that fromDate and toDate are both java.util.Date objects. I'm still not sure how to solve this though.
I figured out the issue. I don't understand the cause, but the issue is with the BasicDBObjectBuilder not using the Date object correctly. I switched to QueryBuilder and built the exact same query and it returned results.
fromDate must be of the type Date not the String representation. An ISODate in the MongoDB storage Engine is not equal to the String representation of the same date and so they do not match.
I am to fix an older project, in which there is a database query gone wrong. In the Table, there is a field
viewTime TIME NOT NULL DEFAULT 0
I need to filter out the rows that actually have 0 as their viewTime:
Criteria query = /* create criteria */;
query.add(Restrictions.gt("viewTime", 0));
However, since viewTime is defined as a Date:
#Temporal(TemporalType.TIME)
private Date viewTime;
I get a casting exception. On the other hand, I have no idea how to create a valid Date object that represents time 0. I can't change the type of the field as well for this.
Any way I can express viewTime > 0 in this Criteria object?
I think you have to compare date object with (00/00/00) but the any API will not produce DATE value like it.
This might your solution convert to null refer this link
It seems to me, that you can try such construction:
Criteria query = /* create criteria */;
query.add(Restrictions.gt("viewTime", new Date(0)));
Inside my entity class I have a column of type timestamp:
#Column(name = "TESTD")
#Temporal(TemporalType.TIMESTAMP)
private Date test_date;
Inside my session bean I'm creating a select query which return a resultList, and then I'm creating from it a json object:
Query query = em.createNamedQuery("findAllTest");
List<entityClass> results = query.getResultList();
JSONSerializer.toJSON((List)results ,jsonConfig);
when creating the json object I want the timestamp column to be formatted (and not to return as object). How can this be done? how can I cast/format the timestamp column according to the date format I want? what is the best way to do this?
I guess you're using json-lib, based on the code sample, and I've never used it, but the javadoc shows that JsonConfig provides the following method:
public void registerJsonValueProcessor(Class propertyType,
JsonValueProcessor jsonValueProcessor)
Registers a JsonValueProcessor.
[Java -> JSON]
So I guess you could use that method, and register a processor for Calendar.class that would transform the Calendar object into a String using the format you want..
I create a second transient getter that returns the date as a String formatted how I want. It's a bit if a hack but works.
I am using Compass to make queries on data inside in memory data structure. It works fine for searching String and enum values, now I want to search dates.
Search criteria are annotated by #SearchRestriction annotation. Example about someDate:
#SearchRestriction(path="fooBar.someDate" type = SearchRestrictionType.EQUAL)
String someDate;
At searchable data SomeDate is annotated like the following:
#SearchableProperty
Date someDate;
SomeDate inside the searchable data is generated with new Date();) and query String is given as 20120802.
Situation on debugger:
This code generates queries like this:
someDate:20120802
Here someDate is the name of the field I am looking for and 20120802 is a date in order yyyyMMdd.
Problem:
No results is returned, when this query is run. I get an empty list. The Date in query is the same as in the Date object.
What is wrong??
Is this wrong way to search Dates with Compass? I can find only range queries about Date, but a search with exact Date or part of exact Date I cannot find.
You need to specify the format for Searchable property [Date]
#SearchableProperty(format = "yyyyMMdd")
To some extent, it relates to Grails: Lucene, Compass Query Builder and date ranges