title: mongodb / mongoose mapreduce - concat all values to single array
body: <p>I am working on a small application running on <strong>node.js</strong>, which connects to <strong>mongodb</strong> through <strong>Mongoose</strong> ORM. One of the Models is a Person model
  Model Schema:</p>
  
  <pre><code>{
      id : Number,
      name : String
      concatVals : String
  }
  </code></pre>
  
  <p>Example:</p>
  
  <pre><code>[
      {
          id : 1,
          name : 'jerry'
          friends : 'adam#peter#robert#steven'
      },
      {
          id : 2,
          name : 'tony'
          friends : 'richard#robert#steven'
      },
      {
          id : 3,
          name : 'mike'
          friends : 'henry#steven#jerry#adam#tony'
      },
      {
          id : 4,
          name : 'peter'
          friends : 'jerry#bill#bobby#steven#mike#paul'
      }
  ]        
  </code></pre>
  
  <p>As you can see, friends field is basically a String containing names separated by '#'. There is an important reason why friends field exists as a string, not an array. So we cannot change its type or structure. 
  This 'friends list' is actually much longer in real database. As you can see, most of these objects will have intersecting friends list (steven appears in multiple documents).</p>
  
  <p><strong>Goal:</strong>
  I need to figure out the way to efficiently split the friends field in each document, turn it into an array and have a list of all distinct <strong>populated</strong> friends of subset of people. So basically the result I want to get when asking for 'tony' and 'mike' persons:</p>
  
  <pre><code>[
    {
      name : jerry,
      id : 1,
      friends : 'adam#peter#robert#steven'
    },
    {
      name : tony,
      id : 2,
      friends : 'richard#robert#steven'
    },
    {
      richard ...
    }, 
    {
      henry ...
    },
    {
      steven ...
    },
    {
      robert ...
    },
    {
      adam ...
    }
  ] // POPULATED friends of tony and mike
  </code></pre>
  
  <p>The thing is that the amount of data is HUGE, so I want to move as much computation as possible to database side, carrying minimum data processing on server side. My solution so far looks like this:</p>
  
  <pre><code>Person.mapReduce({
      map: function() {
          emit(this.name, this.friends.split('#')); 
      },
      reduce: function(key, values) {
          return values;
      },
      query: {
          name: {
              $in: ['tony', 'mike']
          }
      },
              out: 'friends_output'
  }, // at this point we have docs with friends String splitted into array
          function(err, mapReduceObject) {
      mapReducePipeline.aggregate(
              { $unwind: '$value'}, 
              {
          $group: {_id: '$value'} // distinct friend docs
      }, 
              {
                  // combining all distinct friends
          $group: {
              _id: null,
              allValues: { $addToSet: '$_id'}
                  }
      },
      function(err, data) {
          console.log(data[0].allValues)
                  // here I get the list of names, not populated docs
      });
  });
  </code></pre>
  
  <p>This way I am partially fulfilling my goal: I am able to get all <strong>distinct</strong> friends of 'tony' and 'mike'. But I want those friends to be populated and I can't find a good way to populate them during mapreduce. 
  Of course, I can make another DB call inside <strong>function(err, data)</strong> and get Persons using names in query</p>
  
  <pre><code>...
  },
  function(err, data) {
      Persons.find({name : data[0].allValues},
          function(err, friends){
              console.log(friends);
          }
      );
  });
  </code></pre>
  
  <p>but that sums up to total 3 DB calls during this procedure:
  - mapReduce
  - aggregation
  - search query </p>
  
  <p>This last <strong>.find()</strong> call keeps bothering me. Do you see any way to populate friends inside/during mapreduce or aggregate? If you have radically different solution to my problem, please share.</p>