Essa não é uma boa maneira de implementar votos positivos e negativos. Além do framework de agregação não ser um mecanismo para atualizar documentos de forma alguma, você parece ter gravitado para pensar que pode ser uma solução devido à lógica que você deseja implementar. Mas o agregado não atualiza.
O que você quer no seu, bem, vamos chamá-lo de esquema de "pergunta" é uma estrutura como esta:
{
"_id": ObjectId("53f51a844ffa9b02cf01c074"),
"upvoted": [],
"downvoted": [],
"upvoteCount": 0,
"downvoteCount": 0
}
Isso é algo que pode funcionar bem com atualizações atômicas e realmente fornecer algumas informações de estado sobre o objeto ao mesmo tempo.
Para os arrays "upvoted" e "downvoted", vamos considerar que a votação dos "users" tem um valor de ObjectId exclusivo semelhante. Então o que vamos fazer é
$push
ou $pull
de qualquer matriz e também "incrementar/diminuir" os valores do contador junto com cada uma dessas operações. Veja como isso funciona para um upvote:
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 },
}
)
Na verdade, são duas operações, que você pode fazer com o AP de operações em massa Eu também (provavelmente a melhor maneira), mas tem um ponto nisso. A primeira instrução corresponderá apenas a um documento em que o usuário atual tenha um "downvote" registrado na matriz. Como isso, já "enviamos" esse valor de ID do usuário para o array "downvotes". Se não estiver lá, nenhuma atualização é feita. Mas você empurra e puxa dos respectivos arrays e também "incrementa/decrementa" os campos do contador ao mesmo tempo.
Com a segunda declaração, que corresponderá apenas a algo onde a primeira não corresponde, você faz uma avaliação justa de que agora não precisa tocar em "downvotes" e apenas lidar com os campos de upvote. Em ambos os casos, a coisa segura a fazer é certificar-se de que a condição principal é que o valor atual do ID do usuário não esteja presente no array "upvoted".
Para downvotes, os campos são apenas invertidos:
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 },
}
)
Naturalmente você pode ver a progressão lógica para simplesmente cancelar qualquer "upvote/downvote" para o usuário em questão. Além disso, você pode ser esperto sobre isso se quiser e expor as informações em seu cliente para não apenas mostrar se o usuário atual já "votou positivo/desaprovado", mas também controlar as ações de clique e eliminar solicitações desnecessárias.