Mongo query for date range in ISODate format - mongodb

I'm trying to create this query to use with jasper reports but something is wrong with my syntax, i have 2 ISODates in my db and i want to query between then, in this query I use $match and $gt, $lt.
Anyway something is not correct because the console says error but doesn`t specify it.
Obs: The problem is something with the $match and the $lt and $gt. because without them it is possible to query.
Code:
{
runCommand : {
aggregate : 'saleCalculation',
pipeline : [
{
$match: {
processingInfo.modifiedDate: {$gt : ISODate("2016-05-01T09:29:40.572Z")},
{$lt : ISODate("2016-06-01T09:29:40.572Z")}
}
},
{
$project : {
header.documentCode : 1,
header.transactionDate : 1,
header.metadata.entityName : 1,
lines : 1
}
},
{ $unwind : '$lines'},
{ $unwind :'$lines.calculatedTax.details' }
]
}
}
Jasper Manual says i need to do something like that:
http://community.jaspersoft.com/wiki/how-query-mongo-isodate-data-parameter
but i didn't understand that

Try this code :
{
runCommand : {
aggregate : 'saleCalculation',
pipeline : [
{
$match: {
processingInfo.modifiedDate: {$gt : ISODate("2016-05-01T09:29:40.572Z"),
$lt : ISODate("2016-06-01T09:29:40.572Z")}
}
},
{
$project : {
header.documentCode : 1,
header.transactionDate : 1,
header.metadata.entityName : 1,
lines : 1
}
},
{ $unwind : '$lines'},
{ $unwind :'$lines.calculatedTax.details' }
]
}
}

Try with this pipeline. Make sure to use double quotes.
[
{ "$match": {"processingInfo.modifiedDate": { "$gt":ISODate("2010-03-26T18:40:59.000Z"), "$lt":ISODate("2016-09-28T18:40:59.000Z")}}},
{
"$project" : {
"header.documentCode": 1,
"header.transactionDate": 1,
"header.metadata.entityName": 1,
"lines" : 1
}
},
{ "$unwind": "$lines"},
{ "$unwind": "$lines.calculatedTax.details" }
]
I tried this command on mongo shell and it worked without any error.
db.runCommand({"aggregate": "saleCalculation", "pipeline" : [
{ "$match": {"processingInfo.modifiedDate": { "$gt":ISODate("2010-03-26T18:40:59.000Z"), "$lt":ISODate("2016-09-28T18:40:59.000Z")}}},
{
"$project" : {
"header.documentCode": 1,
"header.transactionDate": 1,
"header.metadata.entityName": 1,
"lines" : 1
}
},
{ "$unwind": "$lines"},
{ "$unwind": "$lines.calculatedTax.details" }
]
})

Related

MongoDB Query: How to get the all values of a nested field where parent node is dynamic?

Here is the sample of one of the documents in our collection in MongoDB. I need to get all the values of the NUMBER field from all the documents in this collection with a MongoDB Query. What could be that Query?
{
"_id" : "5w1669ba-3f8a-4695-a585-9fa510d13e59",
"display_title" : "SWE Test Series!",
"production_year" : "2020",
"type" : "series",
"created_timestamp" : 1597940264,
"seasons" : {
"8c399fbc-dc65-4c2e-b86c-5c6289835b45" : {
"number" : "1",
"uuid" : "8c399fbc-dc65-4c2e-b86c-5c6289835b45",
"created_timestamp" : 1597940441
}
}
}
You can do that.
Play
objectToArray makes it easy.
db.collection.aggregate([
{
"$project": {
"a": {
"$objectToArray": "$seasons"
}
}
},
{
"$unwind": "$a"
},
{
$project: {
"a.v.number": 1
}
}
])

Reactive MongoDB Aggregation Framework Lookup stage with pipeline

How to use Reactive MongoDB Aggregation Framework in the case when required pipeline stage isn't available?
I'm interested in lookup stage with pipeline, but in documentation I found only
reactivemongo.api.commands.AggregationFramework.Lookup.apply(from: String, localField: String, foreignField: String, as: String)
Development story
Originally code was equivalent to MongoDB JS code
db.tournament.aggregate([
{ $match : { "tid" : "abacaba"} },
{ $group : { _id : "$t" , "m" : {
{ $sort : { "m" : -1 } },
$push : {"u" : "$uid", "m" : "$m" } }
}},
{ $project : { "p" : { $slice : ["$m", 20]} } }
]);
Performance problem with this code that we pushing everything into array and discarding unneeded data only in projection stage. So after reading StackOverflow answer,
I rewrite it to
{ $match : { "tid" : "abacaba"} },
{ $sort : { "m" : -1 } },
{ $group : { "_id" : "$t"} },
{ $lookup : {
"from" : "tournament",
"let" : { "i" : "$_id" },
"pipeline" : [
{ $match : { "$expr" : { "$eq" : [ "$t", "$$i"] } } },
{ $sort : { "m" : -1 } },
{ $limit : 20 },
{ $project : { "uid" : 1, "m" : 1} }
],
"as" : "p"
}}
]);
but I stuck with translating it to Reactive MongoDB Scala code.
UPD1. I accidentally found piece of code with necessary lookup syntax. And came to another question. How Sharded Collection Restrictions looks in my case when the collection on which I run the aggregate() method is equal to from collection?

How to show columns which are not part of $group clause in aggregate query

I would like to output result of my $unwind operation into another collection and getting duplicate _id error. In order to overcome it I am using $group to produce a new _id field. How can I project extra fields from collection? When I am using $project clause it doesn't output anything.
This one works:
db.audit.aggregate([
{$match: { "date": { $gte : ISODate("2015-01-30T00:00:00.000Z"),
$lt : ISODate("2015-01-31T00:00:00.000Z")
}
}
},
{ $unwind : "$data.items" } ,
{ $group : {
"_id" : {
"_id":"$_id",
"sku":"$data.items.sku"
}
}
},
{
$out : "randomAggregates"
}
]
)
This one doesn't:
db.audit.aggregate([
{$match: { "date": { $gte : ISODate("2015-01-30T00:00:00.000Z"),
$lt : ISODate("2015-01-31T00:00:00.000Z")
}
}
},
{ $unwind : "$data.items" } ,
{ $project: { "ccy" : "$data.crncy",
"coo" : "$data.items.coo",
"order_id" : "$meta.refid"
}
},
{ $group : {
"_id" : {
"_id":"$_id",
"sku":"$data.items.sku"
}
}
},
{
$out : "randomAggregates"
}
]
)
Thank you
Use the $first operator in the $group stage and access the whole document using the $$ROOT variable.
{$group:{"_id":{"_id":"$_id","sku":"$data.items.sku"},
"value":{$first:"$$ROOT"}}}
or,
{$group:{"_id":{"_id":"$_id","sku":"$data.items.sku"},
"field":{$first:"$field"}}} // do this for all the fields.
Your modified code would look like:
db.audit.aggregate([
{$match: { "date": { $gte : ISODate("2015-01-30T00:00:00.000Z"),
$lt : ISODate("2015-01-31T00:00:00.000Z")
}
}
},
{ $unwind : "$data.items" } ,
{$group:{"_id":{"_id":"$_id","sku":"$data.items.sku"},
"value":{$first:"$$ROOT"}}} // you could do it for individual
// fields as well here
{
$out : "randomAggregates"
}
]
)

Dynamic keys from values in MongoDB

Say I have this:
{
"_id" : "ENVD",
"years" : [
{
"year" : "2013",
"avgInstructor" : 5.144999999999998
},
{
"year" : "2012",
"avgInstructor" : 5.194436090225564
}
]
}
I need to be able to find the difference in the avgInstructor field from 2012-13. I was thinking I could transform the keys somehow using a $project which would make the year be the key, and the avgInstructor rating be the value. So it would look like this:
{
"_id" : "ENVD",
"years" : {
"2013" : 5.144999999999998,
"2012" : 5.194436090225564
}
}
Is this possible? Keep in mind my main goal is to be able to run a subtraction like this pseudocode : years['2013'].avgInstructor - years['2013'].avgInstructor. So if you see an easier way, that would be great as well. I am not sure of the best way to go about this in the context of an aggregation pipeline. Can someone help?
For people that ends up here looking for a solution to transform an array to an object using aggregation in a more recent version of MongoDB:
MongoDB 3.4.4 introduced $arrayToObject
You have to $map years
{
$set: {
years: {
$map: {
input: "$years",
as: "year",
in: [
"$$year.year",
"$$year.avgInstructor"
]
}
}
}
}
to be like this
{
"_id" : "ENVD",
"years": [
["2013", 5.144999999999998],
["2012", 5.194436090225564]
]
}
then use $arrayToObject
{
$set: {
years: {
$arrayToObject: "$years"
}
}
}
Or combine the two steps together
{
$set: {
years: {
$arrayToObject: {
$map: {
input: "$years",
as: "year",
in: [
"$$year.year",
"$$year.avgInstructor"
]
}
}
}
}
}
A Possible answer ...
Unwind first
project to make it a little easier to handle
Sort on _id and then on year
group by _id to pickup the first and the last value
final projection to get subtracted value
db.coll.aggregate ( [
{ "$unwind" : "$years" } ,
{ $project : { "year" : "$years.year", "avgInstructor" : "$years.avgInstructor" } },
{ $sort : { "_id" : 1, "year" : 1 } },
{ $group : { "_id" : "$_id", "val_min" : { $first : "$avgInstructor" }, "val_max" : { $last : "$avgInstructor" } } },
{ $project : { "diff" : { $subtract : [ "$val_min", "$val_max" ] } } }
] )

Mongodb count() of internal array

I have the following MongoDB collection db.students:
/* 0 */
{
"id" : "0000",
"name" : "John"
"subjects" : [
{
"professor" : "Smith",
"day" : "Monday"
},
{
"professor" : "Smith",
"day" : "Tuesday"
}
]
}
/* 1 */
{
"id" : "0001",
"name" : "Mike"
"subjects" : [
{
"professor" : "Smith",
"day" : "Monday"
}
]
}
I want to find the number of subjects for a given student. I have a query:
db.students.find({'id':'0000'})
that will return the student document. How do I find the count for 'subjects'? Is it doable in a simple query?
If query will return just one element :
db.students.find({'id':'0000'})[0].subjects.length;
For multiple elements in cursor :
db.students.find({'id':'0000'}).forEach(function(doc) {
print(doc.subjects.length);
})
Do not forget to check existence of subjects either in query or before check .length
You could use the aggregation framework
db.students.aggregate(
[
{ $match : {'_id': '0000'}},
{ $unwind : "$subjects" },
{ $group : { _id : null, number : { $sum : 1 } } }
]
);
The $match stage will filter based on the student's _id
The $unwind stage will deconstruct your subjects array to multiple documents
The $group stage is when the count is done. _id is null because you are doing the count for only one user and only need to count.
You will have a result like :
{ "result" : [ { "_id" : null, "number" : 187 } ], "ok" : 1 }
Just another nice and simple aggregation solution:
db.students.aggregate([
{ $match : { 'id':'0000' } },
{ $project: {
subjectsCount: { $cond: {
if: { $isArray: "$subjects" },
then: { $size: "$subjects" },
else: 0
}
}
}
}
]).then(result => {
// handle result
}).catch(err => {
throw err;
});
Thanks!