2

我试图了解嵌入在 Mongodb 中,但找不到足够好的文档。不建议链接,因为写入在文档之间不是原子的,并且还有两个查找。有人知道如何解决这个问题,或者你会建议我去像neo4j这样的图形数据库。

我正在尝试构建一个需要多对多关系的应用程序。为了解释,我将以图书馆为例。它可以根据他的朋友正在阅读的书籍和邻居(志同道合)用户正在阅读的书籍向用户推荐书籍。

有用户和书籍。用户借书并有其他用户的朋友

  1. 给定一个用户,我需要他正在阅读的所有书籍以及该书的共同朋友数量
  2. 给定一本书,我需要所有正在阅读它的人。可能给了一个用户A,这会返回用户A的读书人和朋友的交集。这是相互的友谊

用户 = [

       { name: 'xyz', 'id':'000000', friend_ids:['949583','958694']}

       { name: 'abc', 'id':'000001', friend_ids:['949582','111111']}

      ]

书籍 = [

      {'book':'da vinci code', 'author': 'dan brown', 'readers'=['949583', '000000']}

      {'book':'iCon', 'author': 'Young', 'readers'=['000000', '000001']}

      ]

如上所示,如果我使用 mongo DB,通常我需要两个文档,因为我可能会进行双向查找。将文档复制(嵌入)到另一个文档中可能会导致大量重复(这些模式可以存储比显示更多的信息)。

我是否正确地建模了我的数据?这可以在 mongodb 中有效地完成,还是我应该查看图形数据库。

4

2 回答 2

6

免责声明:我为 Neo4j 工作

从您的大纲、需求和数据类型来看,您的应用似乎是图形数据库的最佳选择。

我建议你用图形数据库做一个快速的峰值,看看它是怎么回事。

  • 不会有重复
  • 你有原子操作的事务
  • 以下链接是自然操作
  • 本地查询(例如来自用户或一本书)既便宜又快速
  • 您可以使用最短路径等图形算法来查找有关数据的有趣信息
  • 推荐和类似的操作对于图数据库来说是很自然的

一些问题:

  • 你当初为什么选择 MongoDB?
  • 你使用什么实现语言?
于 2012-02-15T00:04:23.180 回答
5

您上面的基本架构建议适用于 MongoDB,但有一些建议:

  1. 使用整数作为标识符,而不是字符串。MongoDB 通常会更紧凑地存储整数(它们将始终为 8 个字节,而字符串的存储大小将取决于字符串的长度)。您可以使用findAndModify来模拟唯一的序列生成器(例如某些关系数据库中的 auto_increment)——有关如何完成此操作的示例,请参见Mongoengine 的 SequenceField 。您还可以使用始终为 12 个字节的ObjectId,但实际上可以保证是唯一的,而无需在数据库中存储任何协调信息。
  2. 您应该使用该_id字段而不是id,因为该字段始终存在于 MongoDB 中,并且在其上创建了默认的唯一索引。这意味着您_id的 s 始终是唯一的,并且查找_id速度非常快。

您是对的,使用这种模式将需要多个find()s,并且每次都会产生网络往返开销。但是,对于您上面建议的每个查询,您需要不超过 2 次查找,并结合一些简单的应用程序代码:

  1. “给定一个用户,我需要他正在阅读的所有书籍以及该书的共同好友数量”

    a。查找有问题的用户,然后
    b。使用 查询图书收藏db.books.find({_id: {$in: [list, of, books, for, the, user]}}),然后使用
    c。对于每本书,计算该书的读者加上用户的朋友的集合并集
  2. “给定一本书,我需要所有正在阅读它的人。”

    一个。查找有问题的书,然后
    b。查找所有正在阅读该书的用户,再次使用$inlikedb.users.find({_id: {$in: [list, of, users, reading, book]}})
  3. “可能给了一个用户A,这会返回用户A的读书人和朋友的交集。”

    一个。查找有问题的用户,然后
    b。查找有问题的书,然后
    c. 计算用户的朋友和书的读者的集合并集

我应该注意,$in如果您有很长的列表,这可能会很慢,因为它实际上相当于对 N 个项目的列表进行 N 次查找。但是,服务器会为您执行此操作,因此它只需要一次网络往返而不是 N。

作为使用$in其中一些查询的替代方法,您可以在数组字段上创建索引,并在集合中查询具有数组中特定值的文档。例如,对于上面的查询 #1,您可以执行以下操作:

// create an index on the array field "readers"
db.books.ensureIndex({readers: 1})

// now find all books for user whose id is 1234
db.books.find({readers: 1234})

这称为多键索引,可以比$in某些情况下执行得更好。您的确切体验将根据文档数量和列表大小而有所不同。

于 2012-02-15T21:07:38.647 回答