我想为文档存储特定于用户的数据。
有一个集合Task
,它包含一般信息,但也应该包含特定于用户的信息。当查询API时,客户端应该只获得请求用户的一般信息和特定信息。
我考虑了不同的方法,最终得到了以下两种方法。请分享你对这类问题的看法和建议,因为我认为这是一个常见的问题。
谢谢。
A-嵌入式阵列
Tasks
包含一组子文档,其中包含每个用户的设置- 在返回任务之前,数组将被用户特定的对象替换,或者对象将与任务本身合并(我更喜欢第一个,这样每个人都可以看到哪些字段是用户特定的)
示例
// Task
{
"title": "brush your teeth",
...
"user_based": [
{
"user": "54182b021a944f9c18897642",
"context": "Work",
"remind": "2014-09-16T12:41:16.412Z",
"last_access": "2014-09-16T12:41:16.412Z"
...
}
]
}
问题
- 需要计算(比较)和操作
- Mongoose支持一种在发送对象之前对其进行操作的方法,但它不能在这里使用,因为当时用户是未知的
B-用户任务集合
Tasks
包含一般信息UserTasks
包含用户特定信息并引用Task
- 查询
UserTasks
并将Task
解析为子文档
示例
// Task
{
"title": "brush your teeth",
...
}
// UserTask
{
"task": "54282b021a944f9c18897642",
"context": "Work",
"remind": "2014-09-16T12:41:16.412Z",
"last_access": "2014-09-16T12:41:16.412Z"
...
}
问题
- 需要解析引用
- 如果存在没有
Task
的UserTasks
,则可能存在不一致 - 如果没有创建
UserTask
,Task
就不可能存在,这会导致其他问题
在我看来,方法B更适合您想要实现的目标。
由于任务请求应该只返回一般信息和请求用户的特定数据,因此在单独的集合中请求它将比在嵌套数组中请求更容易。数据不一致的问题总是可以通过一些preSave和preRemove挂钩来解决,以确保任务至少有一个用户任务,并且用户任务始终连接到任务。
方法A的问题将需要更多的代码来从嵌套数组中提取用户特定的数据并将其返回给用户,方法B的问题将非常简单,而且实际上相当优雅,让我给你举一个例子:
var getTask = function(req, res, next) {
Task.findById(req.params.id, function(err, task) {
if (err) ...
UserTask.findOne({
user: req.user._id,
task: task._id
}, function(err, userTask) {
task.userTask = userTask;
res.json(task);
})
})
};
让我知道这是否合理。
通常,我的目标是使检索数据尽可能简单快捷。
我倾向于选择较少的集合(解决方案A),因为这将减少解析引用的需要。但是,我不想在将数据发送到客户端之前对其进行操作。这为漏洞打开了大门,也许还有安全漏洞。
在这种情况下,我会选择解决方案B。您可以使用mongoose填充功能来减少在mongo中解析引用的痛苦。
// loading all tasks for a user
router.get('/users/:id/tasks', function(req, res, next) {
UserTask.find({_user: req.params.id})
.populate('_tasks')
.exec(function(err, tasks) {
if(err) return next(err);
res.json(tasks)
})
})