Reputation: 724
I have a collection named 'agendas' each agenda has a nested tasks collection winch is referenced object id.
I'm doing a lookup on the tasks collection and then doing a match based on a date range to find all the agenda "items" with tasks between that range. I then do a filter to remove all the tasks. So basically the $match and $filter are the same.
I'm not sure why I'm returning a agenda item with completely filtered tasks[]. I thought any agenda items would be filtered by the $match first.
My Query:
db.agendas.aggregate([
{ '$lookup': {
from: 'tasks',
localField: 'tasks',
foreignField: '_id',
as: 'tasks' } },
{ '$match': {
'$and': [
{ 'tasks.status': 'Closed' },
{ 'tasks.date': { '$gte': new ISODate('2017-10-01T05:00:00.000Z') } },
{ 'tasks.date': { '$lte': new ISODate('2017-10-01T05:00:00.000Z') } }
] } },
{ '$limit': 100 },
{ '$project': {
type: 1, description: 1,
tasks: {
'$filter': {
input: '$tasks',
as: 'tasks',
cond: { '$and': [
{ '$eq': [ '$$tasks.status', 'Closed' ] },
{ '$gte': [ '$$tasks.date', new ISODate('2017-10-01T05:00:00.000Z') ] },
{ '$lte': [ '$$tasks.date', new ISODate('2017-10-01T05:00:00.000Z') ] }
] } } } } },
{ '$group': { _id: '$type', agenda: { '$push': '$$ROOT' } } },
{ '$sort': { _id: 1 } } ], {}).pretty()
Results
{
"_id" : "Maintenance",
"agenda" : [
{
"_id" : ObjectId("59d429ba15c67c147f8f3513"),
"description" : "Some new item 4",
"type" : "Maintenance",
"tasks" : [ ]
}
]
}
{
"_id" : "Monitoring",
"agenda" : [
{
"_id" : ObjectId("59d50d36e6de730a6d85019b"),
"description" : "Some new test agenda for Tomski",
"type" : "Monitoring",
"tasks" : [
{
"_id" : ObjectId("59d5378808f51d0c6590c724"),
"status" : "Closed",
"text" : "Some task 2",
"author" : {
"id" : ObjectId("59c09f8a8b4ad70aa4cda487"),
"name" : "Karunik De"
},
"date" : ISODate("2017-10-01T05:00:00Z"),
"created" : ISODate("2017-10-04T19:33:28.560Z"),
"__v" : 0
}
]
}
]
}
Upvotes: 0
Views: 25
Reputation: 75934
You need to use $elemMatch
when you have multiple criteria and you would like to apply all criteria on each task.
Something like
{
"$match": {
"tasks": {
"$elemMatch": {
"status": "Closed",
"date": {
"$gte": new ISODate('2017-10-01T05:00:00.000Z'),
"$lte": new ISODate('2017-10-01T05:00:00.000Z')
}
}
}
}
}
More here
Compare with below which looks for one task matching each criteria. So you can have single task matching all criterias or three different tasks matching each of criteria to return document.
{
"$match": {
"tasks.status": "Closed",
"tasks.date": {
"$gte": new ISODate('2017-10-01T05:00:00.000Z'),
"$lte": new ISODate('2017-10-01T05:00:00.000Z')
}
}
}
More here
Upvotes: 1