Как моделировать высокореляционные данные в MongoDB

#mongodb #neo4j #nosql #data-modeling #graph-databases

#mongodb #neo4j #nosql #моделирование данных #графические базы данных

Вопрос:

У меня проблема с моделированием данных в MongoDB. Документация, похоже, не предлагает решений, которые работали бы в моем случае.

Мой конкретный вариант использования очень похож на систему друзей Facebook. У меня есть коллекция пользователей, и каждый пользователь может подключаться к другим пользователям, отправляя приглашения, которые либо принимаются, либо отклоняются.Этот механизм будет основополагающим для других функций, таких как вычисление общих друзей, рекомендация наиболее адекватных друзей и т. Д.

Казалось бы, популярными решениями были бы:

  • Встраивание идентификаторов друзей в пользовательский документ в виде массива
  • Встраивание данных друзей в пользовательский документ в виде массива

Но это проблематично — если у кого-то несколько тысяч друзей, то производительность пострадает, а производительность важна для меня.

Моя идея состояла в том, чтобы создать отдельную коллекцию, в которой каждый документ был бы соединением между двумя пользователями. В этом документе могут быть встроенные данные каждого пользователя и соответствующие дополнительные данные, например статус приглашения на подключение. Что вы думаете об этом дизайне?

Кроме того, существуют ли какие-либо проверенные методы обработки таких ситуаций в MongoDB, когда производительность имеет решающее значение? Я также открыт для других предложений dbs, я думал о графических dbs.

Ответ №1:

Этот вариант использования было бы легко обработать в графической базе данных, такой как neo4j.

Например, вы могли бы использовать язык Cypher от neo4j для хранения факта, что пользователь 123 создал приглашение и отправил его нескольким пользователям таким образом:

 MATCH (u:User {id: 123})
CREATE (u)-[:CREATED]->(i:Invitation {id: 999, text: '...', date: ..., location: ...})
UNWIND [234, 345, 456] AS inviteeId
MATCH (u1:User {id: inviteeId})
CREATE (i)-[:INVITED]->(u1)
  

И всякий раз, когда пользователь отвечает, вы можете сохранить его следующим образом:

 MATCH (u:User {id: 345}), (i:Invitation {id: 999})
CREATE (u)-[:RESPONDED {accept: false}]->(i)
  

Наконец, чтобы увидеть отдельных пользователей, которые приняли любое из приглашений пользователя 123:

 MATCH (u:User {id: 123})-[:CREATED]->(:Invitation)<-[:RESPONDED {accept: true}]-(acceptor:User)
RETURN DISTINCT acceptor