流星:如何在文档中查找子文档(minimongo)

Meteor: how to find a subdocument within a document (minimongo)

短版

要在 collection 中查找文档,它是

collection.findOne([...], [...])

如何在文档中查找子文档?

长版

我有一个 collection 条目如下:

db.projects.find()

{
  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: {
    ...
    }
  }
}

(用 coffeescript 编写)

该条目在我的项目中 collection。它在服务器上发布:

server/publications.js

Meteor.publish('projects', function() {
  return Projects.find();
});

..并被客户订阅:

client/projects.js

Meteor.subscribe('projects');

简单。按预期工作。

接下来,我使用一个Session变量来存储一个选中的项目:

Session.set('selectedProject', this.id); 

并在需要时调用它:

Session.get('selectedProject');

没问题。

现在我想搜索 selectedProject 的 ideas 条目并找到已 completed 的第一个 task:假.

经过几个小时的阅读,我认为我接近以下几点:

 ({
   currentTask: function() {
     return Projects.findOne({
       _id: Session.get('selectedProject', {
         'timeline.ideas.task.completed': false
       })
     }, {
       fields: 'timeline.ideas.task'
     });
   }
 });

我想 ^ 可能会尝试 return 一个项目而不是一项任务?

它 return 是这个错误:

Exception in template helper: Error: Match error: Failed Match.OneOf or Match.Optional validation

理论上应该是这样的

selectedProject.findOne(....)

我是否考虑在服务器上使用 $elemMatch?还是我漏掉了一些简单的东西?

请参阅 使用 聚合 的答案。

Meteor 用户:在撰写本文时(版本 1.0.4.1),不支持客户端聚合。

我想将代码保留在客户端上,也想要响应性,所以这是我的解决方案:

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