Това не е добър начин за прилагане на гласове „за“ и „против“. Освен рамката за агрегиране, която не е механизъм за актуализиране на документи по какъвто и да е начин, изглежда сте гравитирали към мисълта, че това може да е решение поради логиката, която искате да приложите. Но агрегатът не се актуализира.
Това, което искате от вашата схема, нека я наречем "въпрос", е структура като тази:
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": [],
"downvoted": [],
"upvoteCount": 0,
"downvoteCount": 0
}
Това е нещо, което може да работи добре с атомарни актуализации и всъщност да ви даде известна информация за състоянието на обекта в същото време.
За масивите с гласуване „за“ и „против“ ще вземем предвид, че гласуването на „потребителите“ има подобна уникална стойност на ObjectId. Така че това, което ще направим, е $push
или $pull
от двата масива и също така "увеличава/намалява" стойностите на брояча заедно с всяка от тези операции.
Ето как работи това за гласуване за:
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
"downvoted": ObjectId("53f51c0a4ffa9b02cf01c075")
},
{
"$push": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": 1, "downvoteCount": -1 },
"$pull": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
}
)
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
},
{
"$push": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": 1 },
}
)
Всъщност това са две операции, които можете да направите с AP за групови операции Аз също (вероятно най-добрият начин наистина), но има смисъл. Първият израз ще съвпадне само с документ, в който текущият потребител има „глас против“, записан в масива. Тъй като вече сме „избутали“ тази стойност на потребителския идентификатор в масива „против гласове“. Ако не е там, тогава не се прави актуализация. Но вие едновременно натискате и изтегляте от съответните масиви и също така едновременно "увеличавате/намалявате" полетата на брояча.
С второто изявление, което ще съвпадне само с нещо, където първото не е, вие правите справедлива преценка, че сега не е нужно да докосвате „против“ и просто да боравите с полетата за гласуване. И в двата случая безопасното нещо, което трябва да направите, е да се уверите, че основното условие е, че текущата стойност на потребителския идентификатор не присъства в масива „upvoted“.
За гласове против полетата просто се обръщат:
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"downvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
"upvoted": ObjectId("53f51c0a4ffa9b02cf01c075")
},
{
"$pull": { "upvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "upvoteCount": -1, "downvoteCount": 1 },
"$push": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
}
)
db.questions.update(
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"downvoted": { "$ne": ObjectId("53f51c0a4ffa9b02cf01c075") }
},
{
"$push": { "downvoted": ObjectId("53f51c0a4ffa9b02cf01c075") },
"$inc": { "downvoteCount": 1 },
}
)
Естествено можете да видите логичната прогресия към просто отмяна на всяко „гласуване за/против“ за въпросния потребител. Освен това можете да бъдете умни по отношение на това, ако искате, и да разкриете информацията във вашия клиент, за да не само показват дали текущият потребител вече е „гласувал за/против“, но и да контролира действията при кликване и да елиминира ненужните заявки.