sql >> Databáze >  >> NoSQL >> MongoDB

Aplikace podobná Twitteru využívající MongoDB

Máte dva možné způsoby, jak může uživatel sledovat jiného uživatele; buď přímo, nebo nepřímo prostřednictvím skupiny, v takovém případě uživatel přímo následuje skupinu. Začněme ukládáním těchto přímých vztahy mezi uživateli a skupinami:

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

Nyní budete chtít umět rychle zjistit, které uživatele uživatel A přímo nebo nepřímo sleduje. Chcete-li toho dosáhnout, můžete denormalizovat skupiny, které uživatel A sleduje. Řekněme, že skupina X a Y jsou definovány následovně:

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

Na základě těchto skupin a přímých vztahů uživatele A můžete generovat předplatné mezi uživateli. Původ(y) předplatného jsou uloženy u každého předplatného. Pro ukázková data by předplatná vypadala takto:

// 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" ] }

Tato předplatná můžete vygenerovat docela snadno pomocí volání map-reduce-finalize pro jednotlivého uživatele. Pokud je skupina aktualizována, stačí znovu spustit map-reduce pro všechny uživatele, kteří skupinu sledují, a odběry budou znovu aktuální.

Zmenšení mapy

Následující funkce redukce mapy vygenerují předplatné pro jednoho uživatele.

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);
}

Poté můžete spustit map-reduce pro jednoho uživatele zadáním dotazu, v tomto případě pro userA .

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

Několik poznámek:

  • Před spuštěním map-reduce pro daného uživatele byste měli smazat předchozí odběry uživatele.
  • Pokud aktualizujete skupinu, měli byste spustit map-reduce pro všechny uživatele, kteří skupinu sledují.

Měl bych poznamenat, že tyto funkce redukce mapy se ukázaly být složitější, než jsem měl na mysli , protože MongoDB nepodporuje pole jako návratové hodnoty funkcí snížení. Teoreticky by funkce mohly bylo mnohem jednodušší, ale nebylo by kompatibilní s MongoDB. Toto složitější řešení však může být použito k redukci všech users vyzvednutí v jediném hovoru, pokud někdy budete muset.




  1. Mongodb -- zahrnout nebo vyloučit určité prvky pomocí ovladače c#

  2. Návrh aplikace s Redis jako úložiště dat. Co? Proč?

  3. Co je operátor $unwind v MongoDB?

  4. Jak provedu dotaz na pole id v Mongoose?