Quelle que soit la façon dont vous structurez votre document global, vous avez essentiellement besoin de deux choses. Il s'agit essentiellement d'une propriété pour un "compte" et une "liste" de ceux qui ont déjà posté leur "j'aime" afin de s'assurer qu'il n'y a pas de doublons soumis. Voici une structure de base :
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3")
"photo": "imagename.png",
"likeCount": 0
"likes": []
}
Quel que soit le cas, il existe un "_id" unique pour votre "poste photo" et toutes les informations que vous souhaitez, mais ensuite les autres champs mentionnés. La propriété "likes" ici est un tableau, qui contiendra les valeurs uniques "_id" des objets "user" de votre système. Ainsi, chaque "utilisateur" a son propre identifiant unique quelque part, soit dans le stockage local, soit dans OpenId ou quelque chose, mais un identifiant unique. Je vais m'en tenir à ObjectId
pour l'exemple.
Lorsque quelqu'un soumet un "J'aime" à une publication, vous souhaitez émettre la déclaration de mise à jour suivante :
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
},
{
"$inc": { "likeCount": 1 },
"$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Maintenant le $inc
l'opération augmentera la valeur de "likeCount" du nombre spécifié, donc augmentez de 1. Le $push
l'opération ajoute l'identifiant unique de l'utilisateur au tableau dans le document pour référence future.
La principale chose importante ici est de conserver une trace des utilisateurs qui ont voté et de ce qui se passe dans la partie "requête" de la déclaration. Outre la sélection du document à mettre à jour par son propre "_id", l'autre chose importante est de vérifier ce tableau "likes" pour s'assurer que l'utilisateur votant actuel n'y est pas déjà.
Il en est de même pour le cas inverse ou "retirer" le "like":
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": ObjectId("54bb2244a3a0f26f885be2a4")
},
{
"$inc": { "likeCount": -1 },
"$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
La principale chose importante ici est les conditions de requête utilisées pour s'assurer qu'aucun document n'est touché si toutes les conditions ne sont pas remplies. Ainsi, le décompte n'augmente pas si l'utilisateur a déjà voté ou diminue si son vote n'était plus réellement présent au moment de la mise à jour.
Bien sûr, il n'est pas pratique de lire un tableau contenant quelques centaines d'entrées dans un document dans une autre partie de votre application. Mais MongoDB a également une manière très standard de gérer cela :
db.photos.find(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
},
{
"photo": 1
"likeCount": 1,
"likes": {
"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
}
}
)
Cette utilisation de $elemMatch
en projection ne renverra l'utilisateur actuel que s'il est présent ou simplement un tableau vide où il ne le sera pas. Cela permet au reste de la logique de votre application de savoir si l'utilisateur actuel a déjà voté ou non.
C'est la technique de base et elle peut fonctionner pour vous telle quelle, mais vous devez savoir que les tableaux intégrés ne doivent pas être étendus à l'infini et qu'il existe également une limite stricte de 16 Mo pour les documents BSON. Le concept est donc solide, mais ne peut tout simplement pas être utilisé seul si vous vous attendez à des milliers de "votes similaires" sur votre contenu. Il existe un concept connu sous le nom de "bucketing" qui est discuté en détail dans cet exemple pour la conception de schéma hybride qui permet à une solution de stocker un volume élevé de "j'aime". Vous pouvez l'utiliser avec les concepts de base ici comme moyen de le faire en volume.