问题
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()}
]
}
]
}
}
回答1:
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
}
回答2:
Meteor users: at the time of writing (version 1.0.4.1), aggregation on the client is not supported.
I wanted to keep the code on the client, and also wanted reactivity, so here's my solution:
db.projects
// simplified structure
{
title: 'awebsite.com'
company: 'a company'
companyID: Random.id()
category: 'website'
starred: false
tasks: [
{
completed: true
name: 'task1'
category: 'ideas'
todos: [
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
]
}
{
completed: false
name: 'task2'
category: 'ideas'
todos: [
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
{todo: 'something', completed: false, todoID: Random.id()}
]
}
]
}
../projects.coffee
Meteor.subscribe 'projects'
Tasks = new (Mongo.Collection)(null) //use (null) to create client-only collection
Template.projects.rendered = ->
results = Projects.findOne { title: 'awebsite.com' },
fields: tasks: 1
_.each results.tasks, (task) ->
Tasks.insert (task)
Template.projects.helpers
currentTask: ->
Tasks.findOne completed: false
来源:https://stackoverflow.com/questions/29164282/find-return-first-matching-subdocument-from-array-meteor-mongo