Reputation: 1712
I have status
collection which has four fields abc, xyz, status, time
I want to create MongoDB query for the below MySql query:
select * from status where abc = false and xyz = true and (status = pending or (status = inprogress and time = "2015-08-04"))
Basically status
can be pending
or inprogress
but if it is inprogress
then time
must be compare.
I have tried to create below MongodDB query but it did not work
db.status.find
{
"abc" : false ,
"xyz" : true ,
"status" : "pending" ,
"$and" : [
{ "status" : "inprogress"} ,
{ "time" : { "$eq" : { "$date" : "2015-08-04"}}}
]
}
I am using Spring MongoDB, I would appreciate if someone can guide me how to create it in Spring Data MongoDb.
Thanks
Upvotes: 1
Views: 7368
Reputation: 50426
There area couple of things wrong with the current query you are trying. The first thing to understand is that all operations are implicitly and "AND" condition unless stated otherwise. Therefore the $or
condition that you are missing here must contain "both" of the status test and other combined "time" conditions like so:
db.status.find({
"abc" : false,
"xyz" : true,
"$or" : [
{ "status" : "pending" },
{
"status" : "inprogress"
"time" : "2015-08-04"
}
]
})
Your SQL representation here also implies that "time" is in fact a string. If it has been stored the same way in your MongoDB document then the above is fine. If not, and the values have been converted to actual Date
objects in BSON, then you must supply a BSON date ( or something that converts ) as an argument. Typically dates are not "exact", so you use a "range" instead:
db.status.find({
"abc" : false,
"xyz" : true,
"$or" : [
{ "status" : "pending" },
{
"status" : "inprogress"
"time" : { "$gte": new Date("2015-08-04"), "$lt": new Date("2015-08-05") }
}
]
})
For spring translation that would be:
Query query = new Query(Criteria.where("abc").is(false)
.and("xyz").is(true)
.orOperator(
Criteria.where("status").is("pending"),
Criteria.where("status").is("inprogress")
.and("time").is("2015-08-04")
)
);
Or with real date object and a range:
DateTime startDay = new DateTime(2015, 8, 4, 0, 0, DateTimeZone.UTC);
Date startDate = startDay.toDate();
Date endDate = startDay.plusDays(1).toDate();
Query query = new Query(Criteria.where("abc").is(false)
.and("xyz").is(true)
.orOperator(
Criteria.where("status").is("pending"),
Criteria.where("status").is("inprogress")
.and("time").gte(startDate).lt(endDate)
)
);
At least from memory that should be correct, as sitting away from an IDE right now. Also note the "chaining" of operators here such as $gte
and $lt
also means an "AND" condition as assigned to the values of the same key.
When dealing with dates, the underlying driver expects all input to match a BSON date be cast as a java.util.Date type from however you instantiate the date.
Upvotes: 2