Count statement in mongodb - mongodb

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
}
}
},
}
}]);

Related

Mongo pipeline projection on sub array

I have the following document:
{
id: "myId",
boundedPlan: {
plannedWeeks: [
0 : {
weekStartDate: date
weekEndDate: date
plannedDays: []
},
...
]
},
unboundedPlan: {
plannedWeeks: [
0 : {
weekStartDate: date
weekEndDate: date
plannedDays: []
},
...
]
}
}
This plan represent some number of weeks in the future. The plan has a bounded or unbounded plan .
(I have the same structure on two different fields, because in the code they correspond to two different classes with different behavior).
I now have to do the following query.
"Get the current plan week given a date"
I wrote the following pipeline:
[
{ "$match" : { "ownerId" : "defaultOwnerId"}},
{ "$project" : {
"boundedPlan" : 1,
"unboundedPlan" : 1,
"plannedWeeks" : {
"$cond" : {
"if" : { "$ne" : ["$boundedPlan", null]}, "then" : "$boundedPlan.plannedWeeks",
"else" : "$unboundedPlan.plannedWeeks"}
}
}
},
{ "$match" : {
"boundedPlan.plannedWeeks" : {
"$elemMatch" : { "weekStart" : { "$lte" : { "$date" : "2021-03-10T00:00:00Z"}}, "weekEnd" : { "$gte" : { "$date" : "2021-03-10T00:00:00Z"}}}},
"$or" : [{
"unboundedPlan.plannedWeeks" : {
"$elemMatch" : { "weekStart" : { "$lte" : { "$date" : "2021-03-10T00:00:00Z"}}, "weekEnd" : { "$gte" : { "$date" : "2021-03-10T00:00:00Z"}}}}
}]}
}
]
The problem is the following:
knowing that Im operating over a plan with an unbounded plan and explicitly setting the second match :
"$match" : {
"unboundedPlan.plannedWeeks" : {
"$elemMatch" : { "weekStart" : { "$lte" : { "$date" : "2021-03-10T00:00:00Z"}}, "weekEnd" : { "$gte" : { "$date" : "2021-03-10T00:00:00Z"}}}},
}
works.
of course I dont know if the plan is from the unbounded or bounded field, so I tried to add the or operator, which causes no selection at all.
Is there something Im missing?
(working with spring data mongo)
Thank you
Ok, found out... I was using the OrOperator class from spring data mongo wrongly:
new Criteria("field1").orOperator(new Criteria("field2"))
is not the same as
new Criteria().orOperator(new Criteria("field1"), new Criteria("field2")

update specific map with multiple condition in mongo array

{
"dictID" : "37528e10-6344-4d93-8a57-35af0bdb6b34",
"dictVersion" : 1,
"addMeasures" : [
{
"measureId" : "f229ba18-0de8-47a1-8a87-88c95edd536a",
"userId" : "3966C3DD-8328-4F18-A061-02A01111763A",
"created" : "2017-01-07T05:47:22.512Z",
"ownerAction" : "NA"
}
],
"deleteMeasures" : [
{
"measureId" : "0b701469-1502-4de4-95de-1ee70ad6c577",
"userId" : "3966C3DD-8328-4F18-A061-02A01111763A",
"created" : "2017-01-07T05:47:35.193Z",
"ownerAction" : "NA"
},
{
"measureId" : "443d1b97-95ae-4410-9302-da3edbad4004",
"userId" : "3966C3DD-8328-4F18-A061-02A01111763A",
"created" : "2017-01-07T05:47:36.062Z",
"ownerAction" : "NA"
},
{
"measureId" : "aa1689c9-8df6-4bff-88a4-274a4f2dc2aa",
"userId" : "3966C3DD-8328-4F18-A061-02A01111763A",
"created" : "2017-01-07T05:47:37.075Z",
"ownerAction" : "NA"
}
]
}
Above is my mongo collection and i want to do the following query:
db.getCollection('DataDictionaryReview').update(
{
$and: [
{ dictID: "37528e10-6344-4d93-8a57-35af0bdb6b34" },
{ dictVersion: 1 },
{ "deleteMeasures.measureId": "aa1689c9-8df6-4bff-88a4-274a4f2dc2aa" },
{ "deleteMeasures.ownerAction": "NA" }
]
},
{
$set: {
"deleteMeasures.$.created": "2017-01-07T06:51:56.983Z",
"deleteMeasures.$.ownerAction": "Reject"
}
}
)
I want to update the last map of deleteMeasures but every time the query is updating first map of deleteMeasures.
This is strange, the query looks okay to me, however I think it needs $elemMatch to get the correct index value.
db.getCollection('DataDictionaryReview').update(
{
dictID: "37528e10-6344-4d93-8a57-35af0bdb6b34",
dictVersion: 1 ,
"deleteMeasures" : { $elemMatch : {"measureId": "aa1689c9-8df6-4bff-88a4-274a4f2dc2aa", "ownerAction": "NA" }}
},
{
$set: {
"deleteMeasures.$.created": "2017-01-07T06:51:56.983Z",
"deleteMeasures.$.ownerAction": "Reject"
}
}
)

need help for mongodb query for between optional parameter

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 } }
] }")

Mongodb : How should I get original Json structure after filter the records based on requirement?

I am new to mongodb.
I have a Json document in collection like :
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"orgid" : {
"KeyValue" : "DD3342",
"service" : "<all>",
"keytype" : "MCN"
}
},
{
"orgid" : {
"notifytype" : {
"optout" : true
},
"keytype" : "MCN",
"keyvalue" : "<all>",
"service" : "MVPN"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "abc.com",
"notifytype" : {
"alert" : true
},
"id" : 123456.0000000000000000
}
},
{
"order" : {
"id" : 135246.0000000000000000,
"date" : "2015-03-17",
"adminemail" : "abc.com"
}
}
]
}
I would like to filter above json document with following condition:
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, {$match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{$group: {_id: "$_id", assignment: {$push: "$assignment"}}}
// ,{$project : { usercbid : $usercbid, defaultnotifytype : 1, calendar : 1, assignment: 1} }
]
)
printjson(result);
Result of above query is :
{
"result" : [
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"alert" : true
},
"id" : 123456
}
}
]
}
],
"ok" : 1
}
But my final result lost the following original content:
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
How should I append above original content with filtered records?
Thanks,
$Fisrt is the operator which helps you getting the required output.
When you do a $Group, the result of the $Group pipeline operator contains only those fields which are specified inside the $Group pipeline operator.
So, from your query we can notice that you are grouping based on "_Id" and you are selecting only "assignment" key field, so the OUTPUT of this group pipeline operator will contain only those 2 fileds ( "_ID" and "assignment" ).
To make sure that the other left out feilds ( usercbid, defaultnotifytype , calendar ) to be part of the $Group pipeline output, we need to mention that explicitly in the Group pipeline using $First as below :
{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
$First Returns the value that results from applying an expression to the first document in a group of documents that share the same group by key.
Please check the below query, it will help you in fetching the required output :
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, { $match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
]
).pretty();

$avg in mongodb aggregation

Document looks like this:
{
"_id" : ObjectId("361de42f1938e89b179dda42"),
"user_id" : "u1",
"evaluator_id" : "e1",
"candidate_id" : ObjectId("54f65356294160421ead3ca1"),
"OVERALL_SCORE" : 150,
"SCORES" : [
{ "NAME" : "asd", "OBTAINED_SCORE" : 30}, { "NAME" : "acd", "OBTAINED_SCORE" : 36}
]
}
Aggregation function:
db.coll.aggregate([ {$unwind:"$SCORES"}, {$group : { _id : { user_id : "$user_id", evaluator_id : "$evaluator_id"}, AVG_SCORE : { $avg : "$SCORES.OBTAINED_SCORE" }}} ])
Suppose if there are two documents with same "user_id" (say u1) and different "evaluator_id" (say e1 and e2).
For example:
1) Average will work like this ((30 + 20) / 2 = 25). This is working for me.
2) But for { evaluator_id : "e1" } document, score is 30 for { "NAME" : "asd" } and { evaluator_id : "e2" } document, score is 0 for { "NAME" : "asd" }. In this case, I want the AVG_SCORE to be 30 only (not (30 + 0) / 2 = 15).
Is it possible through aggregation??
Could any one help me out.
It's possible by placing a $match between the $unwind and $group aggregation pipelines to first filter the arrays which match the specified condition to include in the average computation and that is, score array where the obtained score is not equal to 0 "SCORES.OBTAINED_SCORE" : { $ne : 0 }
db.coll.aggregate([
{
$unwind: "$SCORES"
},
{
$match : {
"SCORES.OBTAINED_SCORE" : { $ne : 0 }
}
},
{
$group : {
_id : {
user_id : "$user_id",
evaluator_id : "$evaluator_id"
},
AVG_SCORE : {
$avg : "$SCORES.OBTAINED_SCORE"
}
}
}
])
For example, the aggregation result for this document:
{
"_id" : ObjectId("5500aaeaa7ef65c7460fa3d9"),
"user_id" : "u1",
"evaluator_id" : "e1",
"candidate_id" : ObjectId("54f65356294160421ead3ca1"),
"OVERALL_SCORE" : 150,
"SCORES" : [
{
"NAME" : "asd",
"OBTAINED_SCORE" : 0
},
{
"NAME" : "acd",
"OBTAINED_SCORE" : 36
}
]
}
will yield:
{
"result" : [
{
"_id" : {
"user_id" : "u1",
"evaluator_id" : "e1"
},
"AVG_SCORE" : 36
}
],
"ok" : 1
}