Mongo模式(嵌入vs引用)



假设我正在设计一个类似Foursquare的服务,根据用户的位置跟踪用户的签到情况。我使用MongoDB作为后端。

这里的前提是用户可以签入到一个位置,因此模式中的集合可能如下所示:

db.places.find()
{ "_id" : ObjectId("4e6a5a58a43a59e451d69351"), "address" : { "street" : "2020 Lombard     St", "city" : "San Francisco", "state" : "CA" }, "latlong" : [ 37.800274, -122.434914 ], "name" : "Marina Sushi", "timezone" : "America/Los_Angeles" }
{ "_id" : ObjectId("4e6a59c3a43a59e451d69350"), "address" : { "street" : "246 Kearny St", "city" : "San Francisco", "state" : "CA" }, "latlong" : [ 37.79054, -122.40361 ], "name" : "Rickhouse", "timezone" : "America/Los_Angeles" }
db.users.find()
{ "_id" : ObjectId("4e936bc1da06d5e081544b8b"), "_class" : "com.gosociety.server.common.model.User", "email" : "goso@gosociety.com", "password" : "asdfasdf"}

所以在上面的集合中,我们有位置和用户。用户可以"签入"到一个地方,因此当用户签入时,我们将在数据库中保存该记录。签入将包括:签入时间(UTC),备注(150个字符),以及是否发送到他的Facebook feed(布尔值)。

根据上面的描述,我可以想到在Mongo中进行模式设计的两种选择:

  • 创建一个签入集合,并使用mongo生成的引用id将其存储在User集合中,并将Places集合作为每个集合中的签入[]。这样就很容易确定每个用户和每个场地的汇总统计信息。

  • 不要创建check- kin collection,而是使用相同的check- kin information更新Place和User数据

我相信我在mongo文档中读到,如果要聚合的数据在没有包含聚合信息的对象的情况下几乎从不显示,则应该直接使用聚合。如果我们遵循foursquare应用程序使用的方法,它只在我们查看用户的个人资料时显示用户的总签到次数,或者在我们查看他们的地点详细信息时显示用户的签到状态。

如有任何建议,我将不胜感激。

谢谢。

我个人倾向于使用单独的集合,主要是为了保持用户/位置对象较小,因为每个用户/位置可以有无限的签入次数。如果您在checkins集合中的user_id/timestampl和place_id/timestamp上添加索引,那么针对特定用户或地点的查询将是有效的。使用单独集合的第二个好处是,MongoDB在增长过大时不必继续移动用户或放置对象。相反,它只会继续添加checkins集合,这应该是相当有效的(每个分片每秒1000次插入的10次)。

我还应该提到,我将在位置或用户文档中存储checkin id,因为在checkin文档中对place_id或user_id进行索引可以获得相同的性能优势。

我同意Rick的观点,尽管您可能希望在您的位置/用户文档(例如totalCheckinCount)中存储关于签入的聚合数据以便快速检索。

对于Rick强调的增长/移动问题来说,这是安全的,因为简单的聚合数据以O(1)的速度增长,而不像存储实际的签入本身,它当然会以O(n)的速度增长,其中n是签入的数量。

最新更新