I am trying to create a custom Query annotation in a MongoRepository. Everything is fine except the date comparison. I need to find all items that were created on a specific day, so I give 2 date objects with the good date and the times fixed to 00:00 and 23:59 to gte and lte operators.
This is the request sent according to the debug trace:
2022-08-27 01:52:25.817 DEBUG 440959 --- [or-http-epoll-4] o.s.data.mongodb.core.MongoTemplate : find using query: { "$and" : [{ "$or" : [{ "$where" : "5 == null"}, { "rating" : 5}]}, { "$or" : [{ "$where" : "null == null"}, { "productId" : null}]}, { "$or" : [{ "$where" : "APPROVEDD == null"}, { "moderationStatus" : "APPROVEDD"}]}, { "$or" : [{ "$where" : "true == false"}, { "clientResponses" : { "$exists" : true, "$not" : { "$size" : 0}}}]}, { "$or" : [{ "$where" : "2022-01-29T23:00:00Z == null || 2022-01-30T22:59:59Z == null"}, { "submissionTime" : { "$gte" : { "$date" : "2022-01-29T23:00:00Z"}, "$lte" : { "$date" : "2022-01-30T22:59:59Z"}}}]}]} fields: Document{{}} for class: class com.company.productreviews.cdpresponseportalapi.model.Review in collection: reviews
Dates seem to be in the good format, but mongo gives me an error (only when I use the date filter of my request):
Query failed with error code 139 and error message 'SyntaxError: identifier starts immediately after numeric literal' on server mongodb-databaserevqa-shard-00-02.xxocp.mongodb.net:27017; nested exception is com.mongodb.MongoQueryException: Query failed with error code 139 and error message 'SyntaxError: identifier starts immediately after numeric literal' on server mongodb-databaserevqa-shard-00-02.xxocp.mongodb.net:27017
My repo:
public interface ReviewRepository extends MongoRepository<Review, String> {
#Query("{ $and : [" +
"{ $or : [ { $where: '?0 == null' }, { 'rating': ?0 } ] }," +
"{ $or : [ { $where: '?1 == null' }, { 'productId': ?1 } ] }," +
"{ $or : [ { $where: '?2 == null' }, { 'moderationStatus': ?2 } ] }," +
"{ $or : [ { $where: '?3 == false' }, { 'clientResponses': { $exists: true, $not: { $size: 0 } } } ] }," +
"{ $or : [ { $where: '?4 == null || ?5 == null' }, { 'submissionTime': { $gte: ?4, $lte: ?5 } } ] }," +
"]}")
List<Review> findAll(Integer rating, Integer productId, String moderationStatus, boolean withAnswersOnly, Date submissionDateStartRange, Date submissionDateEndRange);
Review findOneByReviewId(int reviewId);
}
It seems to be a syntax error when your date value are not null. Wrapping your statement in quote should do the trick. So in your last #Query statement do the following:
"{ $or : [ { $where: '\"?4\" == \"null\" || \"?5\" == \"null\"' }, { 'submissionTime': { $gte: ?4, $lte: ?5 } } ] },"
Related
I have a document which has booking as array of object with start date and end date .
{
"_id" : ObjectId("6053364dc406029c54025d01"),
"id" : "b2f1ba33-3fd8-463a-8f12-6433b111bf6d",
"name" : "Royal Hotel",
"booking" : [
{
"startDate" : "2021-08-01",
"endDate" : "2021-08-25"
}
]
}
{
"_id" : ObjectId("6053364dc406029c54025d11"),
"id" : "b2f1ba33-3fd8-463a-8f12-6433b111bf6f",
"name" : "Paradise",
"booking" : [
{
"startDate" : "2021-08-01",
"endDate" : "2021-08-25"
},
{
"startDate" : "2021-08-29",
"endDate" : "2021-08-30"
}
]
}
I have to find those booking which are available for dates between 2021-08-27 to 2021-08-30 .
I have used below code which is working fine if there is just one element in the array but failing with the above data points
((2021-08-27 < booking.startDate && 2021-08-30 < booking.startDate) ||
(booking.endDate < 2021-08-30 && booking.endDate < 2021-08-27))
How can i query on each element in the array and return that document only if each element of the array satisfy the condition.
Try $elemMatch to match elements in array of object,
match both dates with $gte and $lte in $or condition
db.collection.find({
booking: {
$elemMatch: {
$or: [
{
startDate: {
$gte: "2021-08-27",
$lte: "2021-08-30"
}
},
{
endDate: {
$gte: "2021-08-27",
$lte: "2021-08-30"
}
}
]
}
}
})
Playground
I want to project all the objects from an array, if it matches the given condition.
I have following data
{
_id : 1,
em : 'abc#12s.net',
name : 'NewName',
od :
[
{
"oid" : ObjectId("1234"),
"ca" : ISODate("2016-05-05T13:20:10.718Z")
},
{
"oid" : ObjectId("2345"),
"ca" : ISODate("2016-05-11T13:20:10.718Z")
},
{
"oid" : ObjectId("57766"),
"ca" : ISODate("2016-05-13T13:20:10.718Z")
}
]
},
{
_id : 2,
em : 'ab6c#xyz.net',
name : 'NewName2',
od :
[
{
"oid" : ObjectId("1234"),
"ca" : ISODate("2016-05-11T13:20:10.718Z")
},
{
"oid" : ObjectId("2345"),
"ca" : ISODate("2016-05-12T13:20:10.718Z")
},
{
"oid" : ObjectId("57766"),
"ca" : ISODate("2016-05-05T13:20:10.718Z")
}
]
}
I want to get all the objects from od array, if 'od.ca' comes between range say, if greater than 10th may and less than 15th may.
I tried using aggregate method of mongodb and I am new to this method. My query is as given below.
db.userDetail.aggregate(
{
$match:
{
'od.ca':
{
'$gte': '10/05/2016',
'$lte': '15/05/2016'
},
lo: { '$ne': 'd' }
}
},
{
$redact:
{
$cond:
{
if:
{
$gte: [ "$$od.ca", '10/05/2016' ],
$lte : ["$$od.ca" , '15/05/2016']
},
then: "$$DESCEND",
else: "$$PRUNE"
}
}
})
When I am trying to use this command, getting error :-
assert: command failed: {
"errmsg" : "exception: Use of undefined variable: od",
"code" : 17276,
"ok" : 0
} : aggregate failed
Since I am using mongodb 3.0.0 I can not use $fiter. So I tried using $redact.
Can someone tell me what wrong I am doing? Is the query correct?
Also referred question Since I am not using 3.2 of mongodb (as I have mentioned), can not use the accepted answer of the question.
query explanation:
$match - match documents for criteria - limit documents to process
$unwind - econstructs od array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.
$match - match documents for criteria
$group - this is opposite of $unwind in our case - so we are recreating results array
If you are expecting document like this:
{
"_id" : 2,
"od" : [{
"oid" : 1234,
"ca" : ISODate("2016-05-11T13:20:10.718Z")
}, {
"oid" : 2345,
"ca" : ISODate("2016-05-12T13:20:10.718Z")
}
]
}, {
"_id" : 1,
"od" : [{
"oid" : 2345,
"ca" : ISODate("2016-05-11T13:20:10.718Z")
}, {
"oid" : 57766,
"ca" : ISODate("2016-05-13T13:20:10.718Z")
}
]
}
you can use query bellow:
db.userDetail.aggregate([{
$match : {
"od.ca" : {
$lt : new Date(new Date().setDate(new Date().getDate() + 2)),
$gte : new Date(new Date().setDate(new Date().getDate() - 4))
}
}
}, {
$unwind : "$od"
}, {
$match : {
"od.ca" : {
$lt : new Date(new Date().setDate(new Date().getDate() + 2)),
$gte : new Date(new Date().setDate(new Date().getDate() - 4))
}
}
}, {
$group : {
_id : "$_id",
od : {
$push : "$od"
}
}
}
])
The following query gave me the desired result.
If you are using mongodb-2.6.X up to 3.0.X can use this solution.
var object = {st : "10/05/2016", et : "13/05/2016"};
db.userDetail.aggregate(
[
{
$match:
{
"od.ca":
{
'$gte': new Date(object.st),
'$lte': new Date(object.et)
},
"lo" : {$ne : 'd'}
}
},
{
$project:
{
em: 1,
fna : 1,
lna : 1,
ca :1,
od:
{
"$setDifference":
[{
"$map":
{
"input": "$od",
"as": "o",
"in":
{
"$cond":[
{
"$and":
[
{ "$gte": [ "$$o.ca", new Date(object.st) ] },
{ "$lte": [ "$$o.ca", new Date(object.et) ] },
{ "$ne": [ "$$o.oid", ObjectID(config.pid.toString())
] }
]
},
"$$o",false]
}
}
},[false]
]
}
}
},
{$sort : {_id : 1}}
];
)
If you are using 3.2.X, use $filter to get the result.
I am trying to create mongodb optional query in spring data but getting error. Can anyone please help me to resolve this issue.
Please note this query is for between date range
Below is the query
#Query(value = "{ $and: [
{$or : [ { $where: '?0 == null' } , { createdDate : {$gt : ?0} }]},
{$or : [ { $where: '?1 == null' } , { createdDate : {$lt : ?1} }]}
] }")
Below is the generated query
{ "$and" : [
{ "$or" : [ { "$where" : "{ \"$date\" : \"2016-02-28T18:30:00.000Z\"} == null"} ,
{ "createdDate" : { "$gt" : { "$date" : "2016-02-28T18:30:00.000Z"}}}]} ,
{ "$or" : [ { "$where" : "{ \"$date\" : \"2016-03-11T18:30:00.000Z\"} == null"} ,
{ "createdDate" : { "$lt" : { "$date" : "2016-03-11T18:30:00.000Z"}}}]}
]}
getting below error
org.springframework.data.mongodb.UncategorizedMongoDbException: { "serverUsed" : "localhost:27017" , "waitedMS" : 0 , "ok" : 0.0 , "errmsg" : "Failed to call method" , "code" : 1}; nested exception is com.mongodb.CommandFailureException: { "serverUsed" : "localhost:27017" , "waitedMS" : 0 , "ok" : 0.0 , "errmsg" : "Failed to call method" , "code" : 1}
Your query is not very clear, but from what I understand (based on ?0 and ?1 interpolation and your comments):
#Query(value = "{ $or: [
{$and : [ { toDate: { $exists: false } } , { startDate: { $exists: true } }, { createdDate : {$gt : ?0} }]},
{$and : [ { toDate: { $exists: true } }, { startDate: { $exists: false } } , { createdDate : {$lt : ?1} }]},
{$and : [ { toDate: { $exists: false } }, { startDate: { $exists: false } }
] }")
I have a use case where my query need to find based on 3 optional fields and one of them is pass in as a collection.
The "3 optional fields" part is already solved by this post
Spring Data MongoDB AND/OR query with multiple optional parameters
However, I am runnig into the issue with the $in for the collection filed.
For example, in the following query
{ $and :
[{
$and:
[
{$or : [ { $where: '?0 == null' } , { a : ?0 }]},
{$or : [ { $where: '?1 == null' } , { b : ?1 }]},
{$or : [ { $where: '?2 == null' } , { c : ?2 }]}
]
}]
}
In my case, the field a is actually pass in as a collection, I need to find those object in MongoDB with filed a is $in the collection I passed in.
I have tried with something like this
{ $and :
[{
$and:
[
{$or : [ { $where: '?0 == null' } , { a : { $in : ?0 }}]},
{$or : [ { $where: '?1 == null' } , { b : ?1 }]},
{$or : [ { $where: '?2 == null' } , { c : ?2 }]}
]
}]
}
However, I got NPE for this when I pass in a null collection.
You need to test the collection length, as shown here spring-data-mongo - optional query parameters?
You can also get rid of the top-level $and.
{ $and :
[
{$or : [ { $where: '?0.length == 0' } , { a : { $in : ?0 }}]},
{$or : [ { $where: '?1 == null' } , { b : ?1 }]},
{$or : [ { $where: '?2 == null' } , { c : ?2 }]}
]
}
You actually can't use $in for optional list parameter because when not specified it will be null and $in accept only list. To do that You will have add [] around optional list parameter and then flatten this list like that:
{ $and :
[
{$or : [ { $where: '?0 == null;' },
{ $where: '[].concat.apply([],[?0]).indexOf(this.a) !== -1;'}]},
{$or : [ { $where: '?1 == null' } , { b : ?1 }]},
{$or : [ { $where: '?2 == null' } , { c : ?2 }]}
]
}
use that for mongo version < 3.4 and since 3.4 You can use includes function instead of indexOf
I have the following mysql statement but I'd like to use it with spring mongodb driver for java. How to convert it? Have looked at aggregation but have no clue how to.
SELECT SUM(CASE WHEN CreatedTime BETWEEN ('7:00:00' AND '7:14:59') THEN 1 ELSE 0) as firstCount,
SUM(CASE WHEN CreatedTime BETWEEN ('7:15:00' AND '7:29:59') THEN 1 ELSE 0) as secondCount,
FROM MyTable
Where username='Jim'
Mongo document:
{ _id: ObjectId("5asd3ea3402984ca53"), username: "Jim", comment: "hi", CreatedTime: ISODate("2014-10-15T16:39:26.870Z") }
UPDATE on translating it to java using spring data:
When calling getTemplate().executeCommand(match); I get this:
{ "serverUsed" : "xxxxxxx" , "ok" : 0.0 , "errmsg" : "no such cmd: $match" , "bad cmd" : {
"$match" : { "username" : "Jim"} ,
"$group" : {
"firstCount" : {
"$sum" : {
"$cond" : {
"if" : {
"$and" : [ [ { "$gte" : { "$CreatedTime" : { "$date" : "2014-09-20T16:02:10.924Z"}}} , 1 , 0] ,
[ { "$lte" : { "$CreatedTime" : { "$date": "2014-10-20T15:48:19.744Z"}}} , 1 , 0]]} ,
"then" : { "$ifTrue" : 1} ,
"else" : { "$else" : 0}
}
}
}
}}}
Code that I use to get the JSON is here (its quite long).Query looks about the same that was suggested by #Wizard
What could be the trouble with $match? I read somewhere in Stackoverflow that old versions of mongodb do not support $match but I have Aug-2014 release so that can't be the case.
Like this:
db.MyTable.aggregate([{
$match : {
username : 'Jim'
}
}, {
$group : {
_id : 0,
firstCount : {
$sum : {
$cond : {
"if" : {
$and : [{
$gte : [ "$CreateTime", '7:00:00' ]
}, {
$lte : [ "$CreateTime", '7:14:59' ]
}]
},
"then" : 1,
"else" : 0
}
}
},
secondCount : {
$sum : {
$cond : {
"if" : {
$and : [{
$gte : [ "$CreateTime", '7:15:00' ]
}, {
$lte : [ "$CreateTime", '7:29:59' ]
}]
},
"then" : 1,
"else" : 0
}
}
},
}
}]);