我试图在对象内部切换一个布尔值,这是一个子文档,我很难更新数组中的特定对象。
文件:
"_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);
});
我尝试使用$ set但是它没有成功,因为整个邀请数组被替换为' 接受= 1 ' 我如何切换' 接受'具有特定' ID '的文档字段。
Invitation.$.Accepted
位置运算符不适用于包含数组的字段,因此无法迭代到接受字段
修改
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,首先抛出错误async这里是错误:
error-function () {
if (called) throw new Error("Callback was already called.");
called = true;
fn.apply(root, arguments);
}
答案 0 :(得分: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);
});
});
因此,对于您正在执行的操作,在响应中迭代文档列表没有问题,它只是您也想要迭代数组成员。问题在于发出您需要注意的任何类型的.update()
,然后异步调用就完成了。
所以我使用async.each,但您可能希望async.eachLimit来控制循环。元素的匹配来自positional $
运算符,对应于查询中匹配的数组元素。
它只是JavaScript代码,因此只需"切换" !invite.accepted
的值将反转它。为了获得额外的乐趣,请返回"结果"数组从.findOneAndUpdate()
推送修改过的文档。
答案 1 :(得分: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
}
);
注意:您不需要聚合步骤,因为它实际上什么都不做。