3

부울 값을 하위 문서로 토글하려고하는데 배열 내의 특정 개체를 업데이트하는 데 어려움을 겪고 있습니다.Mongodb에서 집계 업데이트

문헌 :

"_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 
    } 
], 

컨트롤러 :

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); 
}); 

난 $ 설정하지만 '= 1허용 "으로 대체되었다 전체 초대 배열로 밖으로 일 didnt한다하여 시도 어떻게하면 '수락 가능'필드의 토글을 전환 할 수 있습니까? 특히 'ID'과 일치합니다.

Invitation.$.Accepted 

위치 지정 연산자를 반복 할 수 없도록 배열을 포함하는 필드에 적용 doesnot 허용 필드

EDIT :

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); 
    }); 

}); 

컨트롤 제 async.each 내부지고 있지 않은 첫 번째 비동기에 오류가 발생합니다. 오류는 다음과 같습니다.

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

답변

1

필자가 피더 쿼리로 집계 프레임 워크를 사용하는 것이 올바른 작업이라고 생각하지 않습니다. 배열을 개별 문서로 "비정규 화"하는 것뿐입니다. 정말 필요가 없어야합니다. 그냥 대신 문서를 가져올 수 :

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); 
    });  

}); 

그래서 당신이 무엇을하고 있는지에 대한 응답으로 문서의 목록이 반복되는 문제가 없습니다, 당신은 또한뿐만 아니라 배열 구성원을 반복 할 뿐이다. catch는 어떤 종류의 .update()을 발행 할 때 비동기 호출이 완료되었음을 인식해야합니다.

그래서 저는 async.each을 사용하고 있습니다. 그러나 아마도 async.eachLimit이 루핑을 제어하기를 원할 것입니다. 요소의 일치는 positional $ 연산자에서 발생하며 쿼리의 일치하는 배열 요소에 해당합니다.

단지 JavaScript 코드이므로 !invite.accepted으로 값을 "전환"하면 반전됩니다. 추가 재미를 얻으려면 수정 된 문서를 .findOneAndUpdate()에서 푸시하여 "결과"배열을 반환하십시오.

+0

대답 주셔서 감사하지만 async.each https : // github이 오류가 발생합니다.com/caolan/async/issues/610 –

+0

@shaileshshekhawat이 문제는 정의되지 않은 배열 객체에 관한 것입니까? 그래서 어떤 배열 객체가 여기에 정의되어 있지 않습니까? '.find()'의 결과는 문서를 반환해야합니다. 그렇지 않으면 쿼리가 잘못되었습니다. 내부 "Invitation"배열이 정의되지 않은 경우 async.each에 제출하기 전에 해당 값을 테스트 할 수 있습니다. –

+0

@ NeilLunn-query on'.find()'가 이미 정의 된 Invitation 배열을 반환합니다.'console.log (docs)'에서 테스트했지만이 이상한 오류가 계속 발생합니다. –

0

이의 위치 업데이트 연산자를 사용 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 
    } 
); 

참고 : 실제로 아무것도하지 않기 때문에 당신은 집계 단계가 필요하지 않습니다.

+0

위치 연산자를 사용하여 이미 시도했지만이 오류가 발생했습니다. '업데이트 할 필드가 쿼리에도 있어야하기 때문에' –

+0

@shaileshshekhawat 배열이 포함 된 위치 연산자 필드를 적용 할 수 없습니다. 나는 그 문제를 바로 잡기 위해 코드를 편집했다. – joao

관련 문제