sql >> Base de Datos >  >> NoSQL >> MongoDB

Cómo modelar un sistema de votación de Me gusta con MongoDB

No importa cómo estructure su documento general, básicamente hay dos cosas que necesita. Esa es básicamente una propiedad para un "recuento" y una "lista" de aquellos que ya han publicado su "me gusta" para garantizar que no se envíen duplicados. Aquí hay una estructura básica:

{ 
    "_id": ObjectId("54bb201aa3a0f26f885be2a3")
    "photo": "imagename.png",
    "likeCount": 0
    "likes": []
}

Cualquiera que sea el caso, hay un "_id" único para su "publicación de fotos" y cualquier información que desee, pero luego los otros campos como se menciona. La propiedad "me gusta" aquí es una matriz, y va a contener los valores únicos "_id" de los objetos "usuario" en su sistema. Entonces, cada "usuario" tiene su propio identificador único en algún lugar, ya sea en el almacenamiento local o OpenId o algo así, pero un identificador único. Me quedaré con ObjectId para el ejemplo.

Cuando alguien envía un "me gusta" a una publicación, desea emitir la siguiente declaración de actualización:

db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
    },
    {
        "$inc": { "likeCount": 1 },
        "$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)

Ahora el $inc la operación allí aumentará el valor de "likeCount" en el número especificado, así que aumente en 1. El $push La operación agrega el identificador único para el usuario a la matriz en el documento para futuras referencias.

Lo más importante aquí es mantener un registro de los usuarios que votaron y lo que está sucediendo en la parte de "consulta" de la declaración. Además de seleccionar el documento para actualizar por su propio "_id" único, la otra cosa importante es verificar la matriz de "me gusta" para asegurarse de que el usuario votante actual no esté allí ya.

Lo mismo es cierto para el caso inverso o "quitando" el "me gusta":

db.photos.update(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
        "likes": ObjectId("54bb2244a3a0f26f885be2a4")
    },
    {
        "$inc": { "likeCount": -1 },
        "$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
    }
)

Lo más importante aquí son las condiciones de consulta que se utilizan para garantizar que no se toque ningún documento si no se cumplen todas las condiciones. Por lo tanto, el recuento no aumenta si el usuario ya votó ni disminuye si su voto ya no estaba presente en el momento de la actualización.

Por supuesto, no es práctico leer una matriz con un par de cientos de entradas en un documento en cualquier otra parte de su aplicación. Pero MongoDB también tiene una forma muy estándar de manejar eso:

db.photos.find(
    { 
        "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
    },
    { 
       "photo": 1
       "likeCount": 1,
       "likes": { 
          "$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
       }
    }
)

Este uso de $elemMatch en la proyección solo devolverá el usuario actual si está presente o solo una matriz en blanco donde no lo esté. Esto permite que el resto de la lógica de su aplicación sepa si el usuario actual ya ha votado o no.

Esa es la técnica básica y puede funcionar para usted tal como está, pero debe tener en cuenta que las matrices integradas no deben extenderse infinitamente, y también existe un límite estricto de 16 MB en los documentos BSON. Por lo tanto, el concepto es sólido, pero no se puede usar por sí solo si espera miles de "me gusta" en su contenido. Hay un concepto conocido como "depósito" que se analiza con cierto detalle en este ejemplo para el diseño de esquema híbrido que permite una solución para almacenar un gran volumen de "me gusta". Puede verlo para usarlo junto con los conceptos básicos aquí como una forma de hacer esto en volumen.