Ben
Ben

Reputation: 16699

Combining queries in mongodb

One member is part of one or many groups. One group can have one or many members.

Given one member, and the groups he is in, how can I obtain the other members in each of those groups?

var MemberSchema = new Schema(
{
    name: { 
        first:      { type: String },
        last:       { type: String },
    },
    groups:     [ { type: String } ],
    otherMembersInGroups: [ {
        id: { type: Schema.ObjectId, ref: 'Member' } ,
        name: { 
            first:      { type: String },
            last:       { type: String },
        }
    } ],
});

var query = MemberModel.findOne( { _id: objId } );
query.exec( function( err, member ) 
{
    // TODO: get all the members in all the groups that this member is in
    var otherMembersInGroups = magicHere();
    member.otherMembersInGroups = otherMembersInGroup;

    return res.send( 200, member );  
}

My starting point is

var query = MemberModel.find( { groups: "groupNamesHere" } )

but I don't really understand how to combine it with the above.

Also: How do I add this field to the mongoose model correctly? I tried, but there is a lot of duplication (see above). But it seems that without adding it to the model, it doesn't actually get added to the member object?

Upvotes: 0

Views: 82

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151230

For mine I would not be so formal with the "Schema" definition and handle it a little differently. Considering a schema defined like:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var memberSchema = new Schema({

  name: {
    first: { type: String },
    last: { type: String  }
  },
  groups: [ { type: String } ]

});

var Member = mongoose.model( 'Member', memberSchema );

With data like this:

{ 
     "_id" : ObjectId("53708c9865a6272f6e26c9bf"), 
     "groups" : [ "tennis" ], 
     "name" : { "first" : "Ted", "last" : "Logan" }, 
     "__v" : 0
}
{ 
     "_id" : ObjectId("53708cb33905d7846ee2a218"),
     "groups" : [ "tennis", "hockey" ],
     "name" : { "first" : "Bill", "last" : "Preston" }, 
     "__v" : 0
}
{ 
    "_id" : ObjectId("53708cd200155f916e9248f6"),
    "groups" : [ "perl", "hockey" ],
    "name" : { "first" : "Fozzie", "last" : "Bear" },
    "__v" : 0
}
{ 
    "_id" : ObjectId("53708ce7c95556e66ee4967f"), 
    "groups" : [ "perl", "hockey" ],
    "name" : { "first" : "Serena", "last" : "Williams" }, 
    "__v" : 0 
}

The rest of the operation becomes like this:

Member.findOne({ _id: "53708cb33905d7846ee2a218" },function(err,member) {

  Member.find({
    "groups": { "$in": member.groups },
    "_id": { "$nin": [ member._id ] }
  },function(err, others) {

    var data = {
      name: member.name,
      groups: member.groups,
      otherMembers: []
    };

    others.forEach(function(other) {
      var doc = {};
      doc.name = other.name;
      doc._id = other._id;
      data.otherMembers.push( doc );
    });

    console.log( data );

  });

});

Of course replacing that console.log() part with your actual API function. But generally a raw object has less rules to manipulate than a "schema" and is therefore just a bit easier to control your results.

Also make sure you have an index specified in that order where "groups" is the first element in order to optimize this.

Upvotes: 1

Related Questions