MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Приложение, подобно на Twitter, използващо MongoDB

Имате два възможни начина, по които потребителят може да следва друг потребител; пряко или непряко чрез група, в който случай потребителят директно следва групата. Нека започнем със съхраняването на тези директни отношения между потребители и групи:

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

Сега ще искате да можете бързо разберете кои потребители следва потребител А, пряко или непряко. За да постигнете това, можете да денормализирате групите, които потребител А следва. Да кажем, че групите X и Y са дефинирани по следния начин:

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

Въз основа на тези групи и преките връзки, които потребител А има, можете да генерирате абонаменти между потребители. Произходът(ите) на абонамента се съхраняват с всеки абонамент. За примерните данни абонаментите ще изглеждат така:

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

Можете да генерирате тези абонаменти доста лесно, като използвате повикване map-reduce-finalize за отделен потребител. Ако група се актуализира, трябва само да стартирате отново map-reduce за всички потребители, които следват групата и абонаментите ще бъдат актуални отново.

Намаляване на картата

Следните функции за намаляване на картата ще генерират абонаментите за един потребител.

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

След това можете да стартирате map-reduce за един потребител, като посочите заявка, в този случай за userA .

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

Няколко бележки:

  • Трябва да изтриете предишните абонаменти на потребител, преди да стартирате map-reduce за този потребител.
  • Ако актуализирате група, трябва да стартирате map-reduce за всички потребители, които следват групата.

Трябва да отбележа, че тези функции за намаляване на картата се оказаха по-сложни от това, което имах предвид , тъй като MongoDB не поддържа масиви като връщани стойности на функциите за намаляване. На теория функциите могат е много по-просто, но не би било съвместимо с MongoDB. Въпреки това, това по-сложно решение може да се използва за намаляване на картографирането на всички users събиране с едно обаждане, ако някога се наложи.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongoose - използване на Populate върху масив от ObjectId

  2. Как да изравнявам поддокумент на основно ниво в MongoDB?

  3. Как да проверя дали се използва индекс

  4. Как да получа масив от колекцията mongoDB?

  5. rmongodb:използвайки $или в заявка