Actualización sobre el Agregado en Mongodb

estoy intentando cambiar un valor booleano dentro de un objeto, que es un subdocumento, tengo dificultades para actualizar un objeto en particular dentro de una matriz.

Documento:

"_id" : ObjectId("54afaabd88694dc019d3b628") "Invitation" : [ { "__v" : 0, "ID" : ObjectId("54af6ce091324fd00f97a15f"), "__t" : "USER", "_id" : ObjectId("54b4ceb50fc380001bea1752"), "Accepted" : false }, { "__v" : 0, "ID" : ObjectId("54afac5412f5fdcc007a5c4d"), "__t" : "USER", "_id" : ObjectId("54b4cebe0fc380001bea1753"), "Accepted" : false } ], 

Controlador:

 User.aggregate([{$match: {_id: ObjectId(54afaabd88694dc019d3b628)}},{$unwind: '$Invitation'},{$project: {_id: '$_id',Invitation: '$Invitation'}}],function(err,results){ function updateInvitation(_id){ var query = {'_id': _id, 'Invitation.ID': ObjectId("54af6ce091324fd00f97a15f")}; var operator = {$inc: {'Invitation.Accepted': 1}}; User.update(query,operator,{multi:true},function(err,updated){ if(err){ console.log(err); } console.log('updating'+updated); }); } res.jsonp(results); updateInvitation(results[0]._id); }); 

Intenté usar $ set, pero no funcionó en conjunto. La matriz de Invitación se reemplazó con ‘ Aceptado = 1 ‘ ¿Cómo puedo cambiar el campo ‘ Aceptado ‘ del documento con ‘ ID ‘ en particular?

 Invitation.$.Accepted 

El operador posicional no se aplica al campo que contiene la matriz, por lo que no se puede iterar en el campo Aceptado

EDITAR:

 User.find({_id: req.user._id},'Invitation',function(err,docs){ if(err){ console.log(err); } console.log(docs); var results = []; async.each(docs,function(doc,err) { if(err){ console.log('error'+ err); } async.each(docs.Invitation,function(invite,callback) { console.log('second async'); User.update( { '_id': doc._id, 'Invitation._id': invite._id }, { '$set': {'Invitation.$.Accepted': !invite.Accepted}}, function(err,doc) { results.push(doc); console.log('updated'+doc); callback(err); } ); }); },function(err) { if (err) console.log(err); console.log(results); }); }); 

El control no está ingresando al segundo async.each, el error se produce en el primer async aquí es el error:

 error-function () { if (called) throw new Error("Callback was already called."); called = true; fn.apply(root, arguments); } 

Realmente no creo que incluso como consulta de alimentador, el marco de agregación sea la operación correcta para usar aquí. Todo lo que está haciendo es “desnormalizar” la matriz como documentos individuales. Realmente no debería haber necesidad. Solo busca el documento en su lugar:

 var query = {}; // whatever criteria Users.find(query,"Invitation",function(err,docs) { if (err) { console.log(err); var results = []; async.each(docs,function(doc,callback) { async.each(docs.Invitation,function(invite,callback) { Users.findOneAndUpdate( { "_id": doc._id, "Invitation._id": invite._id }, { "$set": { "Invitation.$.Accepted": !invite.Accepted } }, function(err,doc) { results.push( doc ); callback(err); } ); },callback); },function(err) { if (err) console.log(err); console.log(results); }); }); 

Entonces, no hay problema en iterar la lista de documentos en una respuesta por lo que está haciendo, es solo que también desea iterar los miembros de la matriz. El problema se produce cuando se emite cualquier tipo de .update() que debe tener en cuenta para que se complete la llamada asíncrona.

Así que estoy usando async.each pero probablemente quieras que async.eachLimit controle el bucle. La coincidencia del elemento proviene del operador posicional $ , que corresponde al elemento de matriz coincidente en la consulta.

Es solo un código JavaScript, así que simplemente “alterne” el valor con !invite.accepted que lo !invite.accepted . Para mayor diversión, devuelva la matriz de “resultados” presionando el documento modificado desde .findOneAndUpdate() .

Utilice el operador de actualización posicional para esto: http://docs.mongodb.org/manual/reference/operator/update/positional/

 User.update( { "_id": ObjectId("54afaabd88694dc019d3b628"), "Invitation": {"$elemMatch": {"ID" : ObjectId("54af6ce091324fd00f97a15f"), "Accepted":false}} }, { "$set" : { "Invitation.$.Accepted" : true } },{multi:false, upsert:false, safe:true}, function (err, numAffectedDocuments){ // TODO } ); 

Nota: no necesita el paso de agregación ya que en realidad no hace nada.