I have a fairly simple collection:
var Access = new Schema({
userId : { type: ObjectId, index: true },
token : { type: String, index: true },
isOwner : { type: Boolean, index: true },
});
mongoose.model('Access', Access);
var Workspace = new Schema({
name : { type: String, lowercase: true, unique: true},
description : String,
isActive : Boolean,
settings : {
longName : String,
welcomeMessage : String,
countryId : { type: ObjectId, index: true },
},
access : [ Access ],
});
mongoose.model('Workspace', Workspace);
When a user connect, I have a middleware check the token and see if everything is OK. So, I have:
exports.tokenCall = function( req, res, next, token ){
var Workspace = mongoose.model('Workspace'),
User = mongoose.model('User'),
accessEntry;
req.application = {};
// Find the token
Workspace.findOne({ 'access.token': token } , function(err, doc){
if(err){
next( new g.errors.RuntimeError503( err ) );
} else {
if(! doc ){
next( new g.errors.BadtokenError403() );
} else {
accessEntry = doc.access.filter(function(entry){ return entry.token == token; } )[0];
req.application.workspaceId = doc._id;
req.application.workspaceName = doc.name;
req.application.userId = accessEntry.userId;
req.application.login = accessEntry.login;
req.application.token = token;
req.application.workspace = doc; // Contains all of the settings!
next();
}
}
});
}
I am sure you can see my problem here: I run Workspace.findOne({ 'access.token': token } , function(err, doc){
to find the document with the right token. But THEN, I am actually... searching an array (!) to find the actual token I looked for! accessEntry = doc.access.filter(function(entry){ return entry.token == token; } )[0];
I am sure this is not the way to do this -- surely. What if I make a query 4 levels down...?!?
So, what is the right way of doing this?
If you're using Mongo 2.2 you can take advantage of the new $elemMatch
projection operator to only include the matching access
array element in the returned doc:
Workspace.findOne(
{ 'access.token': token },
{ _id: 1, name: 1, access: { $elemMatch: { token: token } } },
function(err, doc) {
// doc contains _id, name, and only the access array elements that match on token