MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Como modelar um sistema de votação de curtidas com o MongoDB


Não importa como você estrutura seu documento geral, há basicamente duas coisas que você precisa. Isso é basicamente uma propriedade para uma "contagem" e uma "lista" de quem já postou seu "curtir" para garantir que não haja duplicatas enviadas. Aqui está uma estrutura básica:
{ 
    "_id": ObjectId("54bb201aa3a0f26f885be2a3")
    "photo": "imagename.png",
    "likeCount": 0
    "likes": []
}

Seja qual for o caso, há um "_id" exclusivo para sua "postagem de foto" e qualquer informação que você queira, mas depois os outros campos, conforme mencionado. A propriedade "likes" aqui é uma matriz, e ela conterá os valores "_id" exclusivos dos objetos "user" em seu sistema. Portanto, cada "usuário" tem seu próprio identificador exclusivo em algum lugar, seja no armazenamento local ou OpenId ou algo assim, mas um identificador exclusivo. Vou ficar com ObjectId para o exemplo.

Quando alguém envia um "curtir" para uma postagem, você deseja emitir a seguinte declaração de atualização:
db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
    },
    {
        "$inc": { "likeCount": 1 },
        "$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)

Agora o $inc operação lá aumentará o valor de "likeCount" pelo número especificado, então aumente em 1. O $push A operação adiciona o identificador exclusivo do usuário à matriz no documento para referência futura.

A principal coisa importante aqui é manter um registro dos usuários que votaram e o que está acontecendo na parte "consulta" da declaração. Além de selecionar o documento a ser atualizado por seu próprio "_id" exclusivo, a outra coisa importante é verificar o array "likes" para garantir que o usuário votante atual já não esteja lá.

O mesmo vale para o caso inverso ou "remover" o "like":
db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": ObjectId("54bb2244a3a0f26f885be2a4")
    },
    {
        "$inc": { "likeCount": -1 },
        "$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)

A principal coisa importante aqui são as condições de consulta que estão sendo usadas para garantir que nenhum documento seja tocado se todas as condições não forem atendidas. Portanto, a contagem não aumenta se o usuário já votou ou diminui se seu voto não estava mais presente no momento da atualização.

É claro que não é prático ler um array com algumas centenas de entradas em um documento em qualquer outra parte do seu aplicativo. Mas o MongoDB também tem uma maneira muito padrão de lidar com isso:
db.photos.find(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
    },
    { 
       "photo": 1
       "likeCount": 1,
       "likes": { 
          "$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
       }
    }
)

Este uso de $elemMatch na projeção só retornará o usuário atual se ele estiver presente ou apenas um array em branco onde não estiver. Isso permite que o restante da lógica do seu aplicativo saiba se o usuário atual já votou ou não.

Essa é a técnica básica e pode funcionar para você como está, mas você deve estar ciente de que as matrizes incorporadas não devem ser estendidas infinitamente e também há um limite rígido de 16 MB em documentos BSON. Portanto, o conceito é sólido, mas não pode ser usado sozinho se você estiver esperando milhares de "votos semelhantes" em seu conteúdo. Existe um conceito conhecido como "bucketing" que é discutido com algum detalhe neste exemplo para o design de esquema híbrido que permite uma solução para armazenar um grande volume de "curtidas". Você pode ver isso para usar junto com os conceitos básicos aqui como uma maneira de fazer isso em volume.