To find a document within a collection, it's
collection.findOne([...], [...])
How do you find a subdocument within a document?
I have a collection entry as below:
{
title: 'company.com'
company: 'A Company'
companyID: Random.id()
category: 'website'
starred: false
timeline: {
ideas: {
task: {
name: 'task1'
completed: true
todos: [
{todo: 'a todo', completed: false, todoID: Random.id()}
{todo: 'a todo', completed: false, todoID: Random.id()}
{todo: 'a todo', completed: false, todoID: Random.id()}
]
}
task: {
name: 'task2'
completed: false
todos: [
{todo: 'another todo', completed: false, todoID: Random.id()}
{todo: 'another todo', completed: false, todoID: Random.id()}
{todo: 'another todo', completed: false, todoID: Random.id()}
]
}
}
development: {
...
}
production: {
...
}
}
}
(written in coffeescript)
The entry is in my Projects collection. It's published on the server:
Meteor.publish('projects', function() {
return Projects.find();
});
.. and subscribed to by the client:
Meteor.subscribe('projects');
Simple. Works as expected.
Next, I use a Session variable to store a project when it is selected:
Session.set('selectedProject', this.id);
and call it when required:
Session.get('selectedProject');
All fine.
Now I want to search the ideas entry of the selectedProject and find the first task that has completed: false.
After a few hours of reading, I think I'm close with the following:
({
currentTask: function() {
return Projects.findOne({
_id: Session.get('selectedProject', {
'timeline.ideas.task.completed': false
})
}, {
fields: 'timeline.ideas.task'
});
}
});
I guess ^ that might try to return one project and not one task?
it returns this error:
Exception in template helper: Error: Match error: Failed Match.OneOf or Match.Optional validation
in theory it should be something like
selectedProject.findOne(....)
do I look at using $elemMatch on the server? or am I missing something simple?
See this answer which uses aggregation.
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:
// 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()}
]
}
]
}
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