好吧,我想你需要把它分成基本的"种类".
您有两个"实体"样式的对象:
您有一个"映射"样式的对象:
您有一个"事务"样式的对象:
Step 1: entity
让我们从简单的开始:User
&;运动
.这确实是两个独立的物体,任何一个都不依赖于另一个物体的存在.两者之间也没有隐含的继承权:用户不属于活动,活动也不属于用户.
当您有两个这样的顶级对象时,它们通常会获得自己的Collection .所以你需要Users
个系列和Camapaigns
个系列.
Step 2: mapping
User运动
目前用于表示N-to-M映射.一般来说,当你有一个N对1的映射时,你可以把N放在1的内部.然而,在N-to-M映射中,您通常必须" Select 一方".
理论上,您可以执行以下操作之一:
- 在每个
User
中列出运动 ID
个
- 在每个
运动
中列出Users ID
个
就我个人而言,我会做#1.你可能会有更多的用户参与活动,你可能会想把数组放在更短的地方.
Step 3: transactional
点击是一种完全不同的野兽.在客观方面,你可以这样想:Clicks
"属于"a User
,Clicks
"属于"a 运动
.所以,从理论上讲,你可以只存储这些对象中任何一个的点击.很容易认为点击属于under个用户或活动.
但如果你真的深入研究,以上的简化确实是有缺陷的.在你的系统中,Clicks
实际上是一个中心对象.事实上,你甚至可以说;活动实际上只是与点击"相关".
看看你正在问的问题/疑问.所有这些问题实际上都围绕着点击.Users & 运动s are not the central object in your data, Clicks are.
此外,点击将成为系统中最丰富的数据.你将获得比其他任何东西都多的点击次数.
在为这样的数据设计模式时,这是最大的障碍.有时,当"父"对象不是最重要的东西时,你需要推开它们.想象一下建立一个简单的Electron 商务系统.很明显,orders
将"属于"users
,但orders
对系统来说是如此重要,它将成为一个"顶级"对象.
Wrapping it up
您可能需要三个系列:
- User -> has list of campaign._id
- 运动
- Clicks -> contains user._id, campaign._id
这应该满足您的所有查询需求:
查看每次点击的信息,如IP、Referer、OS等
db.clicks.find()
看看有多少次点击来自X IP、X Referer和X OS
db.clicks.group()
或跑Map-Reduce.
将每次单击与用户和活动关联
db.clicks.find({user_id : blah})
还可以将点击ID推送到用户和活动中(如果有意义的话).
请注意,如果你有很多点击,你真的需要分析你运行最多的查询.你不能对每个字段都建立索引,所以你通常需要运行Map Reduces来"汇总"这些查询的数据.