Morphia query date range - java

What is the equivalent of the following Mongo query in Morphia?
db.events.find({ "date": { $gte: ISODate("2001-01-01") , $lt: ISODate("2001-01-02")} })
Currently I have the following code
Query<Event> query = dataStore.find(Event.class);
query.field("date").greaterThanOrEq(startDate).field("date").lessThan(endDate);
but it results in the following Mongo query
{ "$and" : [ { "date" : { "$gte" : { "$date" : "2001-01-01T00:00:00.000Z"}}} , { "date" : { "$lt" : { "$date" : "2001-01-02T00:00:00.000Z"}}}]}
I suppose the end result is the same, but the resulting query is more verbose.

Use criteria with add method
Something like
Query<Event> query = datastore.find(Event.class);
query.criteria("date").greaterThanOrEq(startDate).add(query.criteria("date").lessThan(endDate));

You need to create a query then add date range condition like followed.
Query<Event> queryForEvent = ds.createQuery(Event.class);
queryForEvent.field("date").greaterThanOrEq(startDate);
queryForEvent.field("date").lessThan(endDate);
List<Event> eventList = queryForEvent.asList();
Hoping you will find it useful.

Related

Spring MongoDB - write a query with multiple $or conditions

For an assignment I have to write a query with multiple OR conditions.
If I had to write it using MongoDB Query Language it would be trivial
{ $and : [
{ $or : [ { "field1" : "value1" }, { "field2" : "value2" } ] },
{ $or : [ { "field3" : "value3" }, { "field3" : null }, { "field3" : { $exists : true }} ] }
] }
I there a way to achieve this using Spring MongoDB ?
I tried
Query query = new Query();
query.addCriteria(new Criteria().orOperator(
Criteria.where("field1").is("value1"),
Criteria.where("field2").is("value2"),
));
query.addCriteria(new Criteria().orOperator(
Criteria.where("field3").is("value3"),
Criteria.where("field3").is(null),
Criteria.where("field3").exists(false),
));
and also tried
Query query = new Query();
query.addCriteria(
Criteria.where("field3").is("value3")
.orOperator(Criteria.where("field3").is(null))
.orOperator(Criteria.where("field3").exists(false))
.andOperator(
Criteria.where("field1").is("value1")
.orOperator(Criteria.where("field2").is("value2"))
);
I get the following message when trying to execute either queries.
Due to limitations of the com.mongodb.BasicDocument, you can't add a
second '$or' expression specified as [...]
Any help would be greatly appreciated.
You can try with this piece of code:
Criteria firstOrCriteria = new Criteria().orOperator(
Criteria.where("field1").is("value1"),
Criteria.where("field2").is("value2"));
Criteria secondOrCriteria = new Criteria().orOperator(
Criteria.where("field3").is("value3"),
Criteria.where("field3").is(null),
Criteria.where("field3").exists(true));
Criteria andCriteria = new Criteria().andOperator(firstOrCriteria, secondOrCriteria);
Query query = new Query(andCriteria);

Spring Data Mongo: criteria doesn't filter by Date

I need to filter my data from mongo db collection by date.
I created following query for complete this task:
new Criteria(Constants.MONGO_POST_CREATION_DATE).gte(DateUtil.getUTCDate(searchDTO.getStartDate())
this criteria generates following query:
{ "creationTime" : { "$gte" : { "$date" : "2018-10-28T21:00:00.000Z"} , "$lte" : { "$date" : "2019-02-06T08:29:00.000Z"}}}
But i couldn't get any data by using this query. It just returns empty result list. I've found following question on stackoverflow which explains how to write correct query for filtering by Date:
Question
So, with query from that answer i'm able to get expected result from mongo:
{ "creationTime" : { "$gte" : new Date("2019-01-24T21:00:00.000Z") , "$lte" : new Date("2019-02-06T08:29:00.000Z")}}
What do i need to change to force Criteria generate proper query for Date?

How to fetch all the records using the like query in mongodb using java

I want to fetch all the records whose employeeId starts with 123.For this, I thought of using like query with regex.
Sample Records in MongoDB:
============================
{name:"XYZ",employeeID : 123456}
{name:"ABC",employeeID : 123789}
{name:"DEF",employeeID : 214356}
After query, it should retrieve only first two records.
Can anyone please help me out regarding this issue.
Try this
Write Query like this
db.getCollection('employee').find({ $where: "/^123.*/.test(this.employeeID)" })
Result :
/* 1 */
{
"_id" : ObjectId("57d15ab13f239d775c5cc667"),
"name" : "XYZ",
"employeeID" : 123456
}
/* 2 */
{
"_id" : ObjectId("57d15ab13f239d775c5cc668"),
"name" : "ABC",
"employeeID" : 123789
}
Try this:
db.getCollection('test').find({ employeeID: { $regex: /^123.*$/ } })

Spring Data Mongo Template - Counting an array

Mongo document:
{
"_id" : "1",
"array" : [
{
"item" : "item"
},
{
"item" : "item"
}
]
}
My mongo shell query looks like so:
db.getCollection('collectionName').aggregate(
{$match: { _id: "1"}},
{$project: { count: { $size:"$array" }}}
)
Is there anyway to implement this using the Mongo Template from Spring?
So far I have this:
MatchOperation match = new MatchOperation(Criteria.where("_id").is("1"));
ProjectionOperation project = new ProjectionOperation();
Aggregation aggregate = Aggregation.newAggregation(match, project);
mongoTemplate.aggregate(aggregate, collectionName, Integer.class);
I think I am only missing the project logic but I'm not sure if it is possible to do $size or equivalent here.
It's quite possible, the $size operator is supported (see DATAMONGO-979 and its implementation here). Your implementation could follow this example:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
Aggregation agg = new Aggregation(
match(where("_id").is("1")), //
project() //
.and("array") //
.size() //
.as("count")
);
AggregationResults<IntegerCount> results = mongoTemplate.aggregate(
agg, collectionName, Integer.class
);
List<IntegerCount> intCount = results.getMappedResults();
Please find below the sample code. You can change it accordingly for your requirement with collection name, collection name class and array field name.
MatchOperation match = new MatchOperation(Criteria.where("_id").is("1"));
Aggregation aggregate = Aggregation.newAggregation(match, Aggregation.project().and("array").project("size").as("count"));
AggregationResults<CollectionNameClass> aggregateResult = mongoOperations.aggregate(aggregate, "collectionName", <CollectionNameClass>.class);
if (aggregateResult!=null) {
//You can find the "count" as an attrribute inside "result" key
System.out.println("Output ====>" + aggregateResult.getRawResults().get("result"));
System.out.println("Output ====>" + aggregateResult.getRawResults().toMap());
}
Sample output:-
Output ====>[ { "_id" : "3ea8e671-1e64-4cde-bd78-5980049a772b" , "count" : 47}]
Output ====>{serverUsed=127.0.0.1:27017, waitedMS=0, result=[ { "_id" : "3ea8e671-1e64-4cde-bd78-5980049a772b" , "count" : 47}], ok=1.0}
You can write query as
Aggregation aggregate = Aggregation.newAggregation(Aggregation.match(Criteria.where("_id").is(1)),
Aggregation.project().and("array").size().as("count")); mongoTemplate.aggregate(aggregate, collectionName, Integer.class);
It will execute the following query { "aggregate" : "collectionName" , "pipeline" : [ { "$match" : { "_id" : 1}} , { "$project" : { "count" : { "$size" : [ "$array"]}}}]}

MongoDB Java Driver: Multiple Date query

I am trying to create a query using MongoDB Java Driver as part of an aggregation command. Currently I allow a date range or an array of specific dates as an argument. eg
<date>
<start>2013-12-10 00:00:00.000</start>
<end>2013-12-12 23:59:59.999</end>
</date>
or
<date>
<specificDates>2013-12-10 00:00:00.000,2013-12-13 00:00:00.000</specificDates>
</date>
The date range query works fine, I parse and convert the xml into a DBObject that produces the following query in mongo;
{ "$match" : { "d" : { "$gte" : { "$date" : "2013-10-01T00:00:00.000Z"} , "$lt" : { "$date" : "2013-10-04T00:00:00.000Z"}}}}
For the specificDates I want to return only results that occur between 00:00:00.000 on the given day and 00:00:00.000 of the next day. From my pretty basic knowledge of mongo querys i had hoped to do a similar $match as the date range, but have it use $in on an array of date ranges similar to the following;
{ "$match" : { "d" : { "$in" : [ { "$gte" : { "$date" : "2013-10-01T00:00:00.000Z"} , "$lt" : { "$date" : "2013-10-02T00:00:00.000Z"}} , { "$gte" : { "$date" : "2013-10-03T00:00:00.000Z"} , "$lt" : { "$date" : "2013-10-04T00:00:00.000Z"}}]}}}
The above query fails to return any results. I have noticed that $in is not listed in the mongodb manual under the Mongo Aggregation Framework section, but its not throwing any kind of errors that I would have expected for an unsupported operation.
I think the issue may come from this line in the MongoDB Manual;
If the field holds an array, then the $in operator selects the documents whose field holds an array that contains at least one element that matches a value in the specified array (e.g. , , etc.)
In my collection the date isn't stored in an array, I suppose I could store it in the collections in an single element array? (Actually, decided to try this quickly before I posted, no documents returned when the date entry in the document is stored in a single element array)
Document entry example
{ "_id" : ObjectId("52aea5b0065991de1a56d5b0"), "d" : ISODate("2013-12-15T00:00:11.088Z"), "t" : 1501824, "s" : 0, "e" : 601, "tld" : "uk", "y" : "domain:check", "n" : "removed.co.uk" }
Is anyone able to give me some advice as to how I should do this query? Thank you.
EDIT: I left the Java tag here in case anyone needs my DBObject creation code, though it shouldn't be necessary as the queries posted have been generated by my build.
EDIT2: So as Alan Spencer pointed out I should be using $or rather than $in, a working $or function is below (ignore the different formatting like the use of ISODate(), its just copy pasted from the mongo shell rather than getting output from my program)
{ $match : { $or : [ { d : { $gte : ISODate("2013-10-01T00:00:00.000Z"), $lt : ISODate("2013-10-02T00:00:00.000Z") } }, { d : { $gte : ISODate("2013-10-03T00:00:00.000Z"), $lt : ISODate("2013-10-04T00:00:00.000Z") } } ] } }
I think you're inverting the meaning of the $in.
$in is used to match exactly against a list of possible values, like
{"color":{"$in": ["red","green","blue"]}}
For your use case, you are trying to match if it satisfies the first or second, etc. So, you can use $or - http://docs.mongodb.org/manual/reference/operator/query/or/
{ "$match" : { "d" : { "$or" : [ { "$gte" : { "$date" : "2013-10-01T00:00:00.000Z"} , "$lt" : { "$date" : "2013-10-02T00:00:00.000Z"}} , { "$gte" : { "$date" : "2013-10-03T00:00:00.000Z"} , "$lt" : { "$date" : "2013-10-04T00:00:00.000Z"}}]}}}

Categories