2015-01-18 3 views
9

Derzeit arbeite ich an einer mobilen App. Grundsätzlich können Leute ihre Fotos posten und die Follower mögen die Fotos wie Instagram. Ich benutze mongodb als Datenbank. Wie bei Instagram, gibt es viele Likes für einzelne Fotos. Das Verwenden eines Dokuments für ein einzelnes "Gefällt mir" mit Index erscheint daher nicht sinnvoll, da es viel Speicherplatz verschwendet. Ich möchte jedoch, dass ein Benutzer schnell ein Like hinzufügt. Also meine Frage ist, wie man das "Gefällt mir" modelliert? Grundsätzlich ist das Datenmodell ähnlich wie Instagram, aber mit Mongodb.Wie man ein "Gefällt mir" -Stimmsystem mit MongoDB modelliert

+0

Sie könnten für jedes Dokument ein "Likes" -Feld haben, das auf ein Foto zeigt. und verwenden Sie den Operator '$ inc', um das Feld pro Dokument auf atomare Weise zu aktualisieren. Aber wenn Sie Ihre aktuelle Dokumentstruktur posten und Ihre Anforderung richtig formulieren könnten, würden Sie gute Antworten bekommen. – BatScream

+2

Hinzufügen von Likes wird extrem einfach und schnell, Sie können alle benötigten Daten direkt an den Server übergeben und buchstäblich eine Abfrage direkt in die DB einfügen. Sie werden jedoch die gleiche Anzahl an Caches speichern und aggregieren, da das Zählen dieser Likes unangenehm ist. Die meisten Websites, einschließlich Instagram, verwenden einen Zähler, wie @BatScream sagt mit $ inc (oder was auch immer in der Technologie, die sie verwenden), um die Likes Existenz Cache, so dass es einfach zu sagen, wie viele mag etwas hat – Sammaye

Antwort

23

Egal, wie Sie Ihr gesamtes Dokument strukturieren, gibt es grundsätzlich zwei Dinge, die Sie brauchen. Das ist im Grunde eine Eigenschaft von vier "Zählung" und einer "Liste" von denen, die dort bereits "Gefällt mir" gepostet haben, um sicherzustellen, dass keine Duplikate eingereicht werden. Hier ist eine Grundstruktur:

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

Was auch immer der Fall ist, gibt es eine einzigartige „_id“ für Ihre „Foto Post“ und was auch immer Informationen, die Sie wollen, aber dann die anderen Felder, wie erwähnt. Die Eigenschaft "Likes" ist hier ein Array, das die eindeutigen "_id" -Werte von den "Benutzer" -Objekten in Ihrem System enthält. Jeder "Benutzer" hat also seine eigene eindeutige Kennung irgendwo im lokalen Speicher oder in OpenId oder so, aber eine eindeutige Kennung. Ich bleibe bei für das Beispiel.

Wenn jemand ein „gefällt mir“ auf einen Beitrag einreicht, möchten Sie das folgende Update-Anweisung erteilen: angegeben, so

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

Nun ist die $inc Betrieb wird es erhöhen den Wert von „likeCount“ durch die Anzahl um 1 erhöhen. Die Operation fügt die eindeutige ID für den Benutzer dem Array im Dokument zur späteren Referenz hinzu.

Die wichtigste Sache hier ist, eine Aufzeichnung der Benutzer, die abgestimmt haben und was passiert in der "Abfrage" Teil der Aussage zu halten. Abgesehen von der Auswahl des zu aktualisierenden Dokuments durch seine eigene eindeutige "_id", ist die andere wichtige Sache, das Array "Likes" zu überprüfen, um sicherzustellen, dass der aktuelle Abstimmungsbenutzer nicht bereits dort ist.

Das gleiche gilt für den umgekehrten Fall oder „Entfernen“, das „wie“:

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

Das Haupt hier wichtige Sache, die Abfragebedingungen verwendet wird, um sicherzustellen, dass kein Dokument, wenn alle Bedingungen berührt wird nicht erfüllt sind. Die Anzahl erhöht sich also nicht, wenn der Benutzer bereits gewählt hat, oder sinkt, wenn seine Stimme zum Zeitpunkt des Updates nicht mehr vorhanden war.

Natürlich ist es nicht praktisch, ein Array mit ein paar hundert Einträgen in einem Dokument in einem anderen Teil Ihrer Anwendung zu lesen. Aber MongoDB hat eine sehr übliche Weise zu handhaben, dass auch:

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

Diese Verwendung von $elemMatch in der Projektion wird nur die aktuellen Benutzer zurück, wenn sie vorhanden sind oder einfach nur ein leeres Array, wo sie nicht sind. Dadurch kann der Rest Ihrer Anwendungslogik erkennen, ob der aktuelle Benutzer bereits eine Abstimmung vorgenommen hat oder nicht.

Das ist die grundlegende Technik und kann für Sie so funktionieren, aber Sie sollten beachten, dass eingebettete Arrays nicht unendlich erweitert werden sollten, und es gibt auch eine harte Grenze von 16 MB für BSON-Dokumente. Das Konzept ist also solide, kann aber nicht alleine verwendet werden, wenn Sie 1000 "Like Votes" für Ihre Inhalte erwarten.Es gibt ein Konzept, das als "Bucketing" bekannt ist und in diesem Beispiel für Hybrid Schema design ausführlich beschrieben wird, das eine Lösung zum Speichern einer großen Menge von "Likes" ermöglicht. Sie können sich das hier zusammen mit den grundlegenden Konzepten ansehen, um dies auf Datenträger zu tun.

+1

Schöne Antwort, tut mir leid für bringen Das ist aber deine Idee, eine Lösung wie diese zu implementieren (anstatt ein Unterdokument zu verwenden, um Likes oder Stimmen zu behalten) http://stackoverflow.com/questions/26914380/schema-for-user-ratings-key-value-db – Disposer

+0

@Disposer Die allgemeine Idee hier ist es, es so einfach wie möglich zu machen, um zu überprüfen, ob jemand abgestimmt hat oder nicht und eine Gesamtzahl der Stimmen ohne Aggregation oder zumindest durch Aufteilen in so wenig Dokumente wie möglich zurückzulesen. Andere Modelle beruhen entweder auf Aggregation in Echtzeit oder sind in Aktualisierungen nicht atomar. Schnell zu schreiben und schnell zu lesen. Für Gegenstände mit hoher Aktivität ist das normalerweise das, was Sie wollen. –

+0

@Neil Lunn. Danke für deine Antwort. Tatsächlich ist meine Datenstruktur sehr ähnlich zu Ihrer und ich plane, ein Bucketing-Design zu verwenden. Ich habe mich gefragt, wie gut es ist, viele Eimer Likes mit dem $ elemMatch-Operator nachzuschlagen. Sagen wir, es gibt 30,0000 Likes eines Fotos, ich habe 300 Eimer und jeder Eimer enthält 1000 Likes. Ist es effizient zu wissen, ob der aktuelle Benutzer bereits eine Stimme abgegeben hat oder nicht? Und ich bin auch interessiert an "Andere Modelle, die entweder auf Aggregation in Echtzeit beruhen", die Sie erwähnt haben, können Sie mehr erklären, so dass ich mehr Optionen bewerten kann? – user2914635

Verwandte Themen