how do I find and return the first subdocument in the 'tasks' array that matches completed: true?
using findOne
returns the entire document.. is there another function for returning a subdocument?
{
title: 'awebsite.com'
company: 'a company'
companyID: Random.id()
category: 'website'
starred: false
timeline: {
tasks: [
{
name: 'task1'
completed: true
todos: [
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
]
}
{
name: 'task2'
completed: false
todos: [
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
]
}
]
}
}
You can do this by aggregation where you can take advantage of an index and limit with the $match
pipeline. Use the $unwind
operator to deconstruct your tasks array into a stream of documents that can then be matched. since you would want to return only "the first subdocument in the 'tasks' array that matches completed: true", you could use the $limit
operator in the last pipeline stage to return only one subdocument:
db.collection.aggregate([
{
$match: {
"timeline.tasks.completed": true
}
},
{
$unwind: "$timeline.tasks"
},
{
$match: {
"timeline.tasks.completed": true
}
},
{
$group: {
_id: {
"tasks": "$timeline.tasks"
}
}
},
{
$project: {
_id: 0,
tasks: "$_id.tasks"
}
},
{
$limit: 1
}
])
Results in:
{
"result" : [
{
"tasks" : {
"name" : "task1",
"completed" : true,
"todos" : [
{
"todo" : "something",
"completed" : false,
"todoID" : "jfoe84jn"
},
{
"todo" : "something",
"completed" : false,
"todoID" : "yr934hjs"
},
{
"todo" : "something",
"completed" : false,
"todoID" : "84hdkl0t"
}
]
}
}
],
"ok" : 1
}