sql >> Database teknologi >  >> NoSQL >> MongoDB

Twitter-lignende app ved hjælp af MongoDB

Du har to mulige måder, hvorpå en bruger kan følge en anden bruger; enten direkte eller indirekte gennem en gruppe, i hvilket tilfælde brugeren direkte følger gruppen. Lad os begynde med at gemme disse direkte relationer mellem brugere og grupper:

{
  _id: "userA",
  followingUsers: [ "userB", "userC" ],
  followingGroups: [ "groupX", "groupY" ]
}

Nu vil du gerne være i stand til hurtigt finde ud af, hvilke brugere bruger A følger, enten direkte eller indirekte. For at opnå dette kan du denormalisere de grupper, som bruger A følger. Lad os sige, at gruppe X og Y er defineret som følger:

{
  _id: "groupX",
  members: [ "userC", "userD" ]
},
{
  _id: "groupY",
  members: [ "userD", "userE" ]
}

Baseret på disse grupper, og de direkte relationer bruger A har, kan du generere abonnementer mellem brugere. Oprindelsen af ​​et abonnement gemmes sammen med hvert abonnement. For eksempeldataene vil abonnementerne se sådan ud:

// abusing exclamation mark to indicate a direct relation
{ ownerId: "userA", userId: "userB", origins: [ "!" ] },
{ ownerId: "userA", userId: "userC", origins: [ "!", "groupX" ] },
{ ownerId: "userA", userId: "userD", origins: [ "groupX", "groupY" ] },
{ ownerId: "userA", userId: "userE", origins: [ "groupY" ] }

Du kan generere disse abonnementer ret nemt ved at bruge et kort-reducer-afslut-opkald for en individuel bruger. Hvis en gruppe opdateres, skal du kun køre kort-reducering igen for alle brugere, der følger gruppen, og abonnementerne vil være opdaterede igen.

Kort-reducer

Følgende kort-reducer-funktioner genererer abonnementerne for en enkelt bruger.

map = function () {
  ownerId = this._id;

  this.followingUsers.forEach(function (userId) {
    emit({ ownerId: ownerId, userId: userId } , { origins: [ "!" ] });
  });

  this.followingGroups.forEach(function (groupId) {
    group = db.groups.findOne({ _id: groupId });

    group.members.forEach(function (userId) {
      emit({ ownerId: ownerId, userId: userId } , { origins: [ group._id ] });
    });
  });
}

reduce = function (key, values) {
  origins = [];

  values.forEach(function (value) {
    origins = origins.concat(value.origins);
  });

  return { origins: origins };
}

finalize = function (key, value) {
  db.subscriptions.update(key, { $set: { origins: value.origins }}, true);
}

Du kan derefter køre map-reduce for en enkelt bruger ved at angive en forespørgsel, i dette tilfælde for userA .

db.users.mapReduce(map, reduce, { finalize: finalize, query: { _id: "userA" }})

Et par bemærkninger:

  • Du bør slette en brugers tidligere abonnementer, før du kører kort-reducering for denne bruger.
  • Hvis du opdaterer en gruppe, bør du køre map-reduce for alle de brugere, der følger gruppen.

Jeg bør bemærke, at disse kort-reducerende funktioner viste sig at være mere komplekse end hvad jeg havde i tankerne , fordi MongoDB ikke understøtter arrays som returværdier for reducere-funktioner. I teorien kunne funktionerne være meget enklere, men ville ikke være kompatibel med MongoDB. Denne mere komplekse løsning kan dog bruges til at kortreducere hele users indsamling i et enkelt opkald, hvis du nogensinde bliver nødt til det.




  1. Hvordan genvinder man slettet plads uden `db.repairDatabase()`?

  2. Visning af alle samlinger i en mongo-database i et nodejs-script

  3. Samtidighed i gopkg.in/mgo.v2 (Mongo, Go)

  4. Sådan konfigurerer du Yii2 med Redis-konfiguration