Find & return first matching subdocument from array (Meteor / Mongo)

自古美人都是妖i 提交于 2019-12-24 17:15:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!