好的,我认为你需要将其分解为基本的“品种”。
您有两个“实体”样式的对象:
您有一个“映射”样式的对象:
您有一个“事务”样式的对象:
第1步:实体
让我们从简单的开始:User
& Campaign
。它们确实是两个独立的对象,没有一个对象真正依赖于另一个对象的存在。两者之间也没有隐式的层次结构:用户不属于营销活动,营销活动也不属于用户。
当你有两个像这样的顶级对象时,它们通常会获得自己的收藏。所以你会想要一个Users
集合和一个Camapaigns
收藏。
第 2 步:映射
UserCampaign
目前用于表示 N 到 M 的映射。现在,一般来说,当您有 N 到 1 的映射时,您可以将 N 放在 1 的内部。但是,对于 N 到 M 的映射,您通常必须“选择一边”。
理论上,您可以执行以下操作之一:
- 列一个清单
Campaign ID
每个里面都有User
- 列一个清单
Users ID
每个里面都有Campaign
就我个人而言,我会做#1。您可能有更多的用户参与营销活动,并且您可能希望将数组放在更短的位置。
第三步:交易
Clicks 确实是一个完全不同的野兽。从客观角度来看,你可以这样想:Clicks
“属于”一个User
, Clicks
“属于”一个Campaign
。因此,从理论上讲,您可以将点击存储为这些对象中的任何一个的一部分。人们很容易认为点击属于under用户或活动。
但如果真正深入挖掘的话,上面的简化确实是有缺陷的。在你的系统中,Clicks
确实是一个中心对象。事实上,您甚至可以说用户和营销活动实际上只是与点击“相关”。
查看您提出的问题/疑问。所有这些问题实际上都围绕着点击。用户和营销活动不是数据中的中心对象,点击才是。
此外,点击将是您系统中最丰富的数据。您将获得比其他任何东西都多的点击次数。
这是为此类数据设计模式时最大的问题。有时,当“父”对象不是最重要的事情时,您需要推迟它们。想象一下构建一个简单的电子商务系统。很明显orders
将“属于”users
, but orders
对于系统来说是如此重要,以至于它将成为一个“顶级”对象。
把它包起来
您可能需要三个集合:
- 用户 -> 有活动列表._id
- Campaign
- 点击次数 -> 包含 user._id、campaign._id
这应该满足您的所有查询需求:
查看每次点击的信息,如 IP、Referer、操作系统等
db.clicks.find()
查看来自 X IP、X Referer、X OS 的点击次数
db.clicks.group()
或运行映射减少.
将每次点击与用户和营销活动相关联
db.clicks.find({user_id : blah})
还可以将点击 ID 推送到用户和营销活动中(如果有意义的话)。
请注意,如果您有大量的点击,您确实必须分析您运行最多的查询。您无法对每个字段建立索引,因此您通常需要运行 Map-Reduce 来“汇总”这些查询的数据。