我用猫鼬做这个 API Put 请求正确吗?

Posted

技术标签:

【中文标题】我用猫鼬做这个 API Put 请求正确吗?【英文标题】:Am I doing this API Put request correct with mongoose? 【发布时间】:2016-10-22 00:29:38 【问题描述】:

所以我正在使用 mongoose 和 mongodb 并使用 express 路由来做到这一点。

我有一个创建时包含空数组的用户文档-“todolist”,我希望能够对其进行编辑以将任务添加到列表中以及编辑这些任务。

现在我在想最好的方法是让服务器检查 req.body 是否设置了某些变量以了解我需要编辑文档的哪个部分。

这是正确的方法还是我想为这样的事情创建一个新的 API 路由,或者我是否通过检查客户端的 req 变量来确定我想在服务器上编辑什么来正确地做到这一点?还有更清洁的方法吗?

router.put('/:user_id', function(req, res) 
    User.findById(req.params.user_id, function(err, user)
        if(err)
            res.send(err);
            return err;
        

        if(req.body.createTask) 
            user.todolist.push(
                "task_name": req.body.task_name,
                "task_importance": req.body.importance,
                "task_completed": false
            )
        else if(req.body.edit_task)
            if(req.body.edit_task_name) 
                user.todolist[req.body.index].task_name = req.body.new_task_name;
            else if(req.body.edit_task_importance) 
                user.todolist[req.body.index].task_importance = req.body.new_task_importance;
            else if(req.body.edit_task_completed) 
                user.todolist[req.body.index].task_completed = true;
            
        

        user.save(function(err)
            if(err)
                res.send(err);
            res.json(message: 'User updated');
        )
    )
);

【问题讨论】:

【参考方案1】:

我建议您使用适当的实体对数据库进行建模,与 User 分开创建 Task 模型并添加对 User 的引用,如下所示:

var TaskSchema = new mongoose.Schema(
  user: 
    type: mongoose.Schema.ObjectId,
    ref: 'User'
  ,
  name: String,
  importance: String,
  completed: Boolean
);

如果你愿意,你也可以在 User 上添加对 Task 的引用:

var User = new mongoose.Schema(
  // note this is an array
  todolist: [
    type: mongoose.Schema.ObjectId,
    ref: 'Task'
  ]
);

这样做,为了让事情更简单,你应该创建一个pre save hook 来自动向用户添加任务:

TaskSchema.pre('save', function(next) 
  if (this.isModified('user') && this.user) 
    // $addToSet will add this document to the user's todolist (if it's not already there)
    User.findOneAndUpdate(_id: this.user, $addToSet: todolist: this, function(err, doc) 
      next(err);
    )
   else 
    next();
  
);

这样,正确的方法是提供与实体相关的端点。因此,要创建一个任务,用户应该请求 POST /tasks 和正文 user: '123', name: 'name', ...

router.post('/tasks', function(req, res) 
  Task.create(req.body, function(err, task) 
    if (err) return res.status(500).send(err);
    return res.status(201).json(task);
  );
);

它将使用我们的预保存挂钩自动将任务添加到用户123。 要编辑任务,只需在任务端点上进行:

router.put('/tasks/:id', function(req, res) 
  Task.findById(req.params.id, function(err, task) 
    if (err) return res.status(500).send(err);
    if (!task) return res.status(404).send('Not Found');

    task.name = req.body.name || task.name;
    task.importance = req.body.importance || task.importance;
    task.completed = true;

    task.save(function(err, task) 
      if (err) return res.status(500).send(err);
      res.status(200).json(task);
    );
  );
);

您不需要编辑用户,因为它只保留任务参考。

如果您想让用户填充任务数据(而不仅仅是他们的 ID),只需执行以下操作:

router.get('/users', function(req, res) 
  User.find().populate('todolist').exec(function(err, users) 
    ...
  );
);

对于像上面这样的查询,我建议您使用像 querymen 这样的库,它将查询字符串(例如 GET /users?q=Some+Search&limit=10&page=2)解析为 MongoDB 查询参数。

希望对您有所帮助。 :)

【讨论】:

这种情况是否会更好地将所有数据保留在用户的架构中?由于每个用户只有一组任务,不会有很多任务 这是您应该做出的决定。我建议您将它们分开,因为将来随着系统的增长,您可以更灵活地改进任务实体,而无需编辑用户实体。 另外,为了可扩展性,最好将小集合分开而不是大集合。了解更多here 如果您仍然想在用户中嵌入任务(这没有错),我建议您创建像 POST /users/:userId/tasksPUT /users/:userId/tasks/:taskId 这样的端点以更清晰。 好的,谢谢。我整天都在想的另一个问题..(这是我第一次制作一个宁静的 api 顺便说一句)但是发出 api 请求的客户端如何知道用户 ID 如果它使用用户,它会不会更好地工作名称而不是 id?

以上是关于我用猫鼬做这个 API Put 请求正确吗?的主要内容,如果未能解决你的问题,请参考以下文章

用猫鼬增加一个值?

MERN API 请求,不知道如何发出 put 请求并正确更新

用猫鼬存储时间的数据类型

我可以为 POST 和 PUT API 请求使用自定义 JsonSerializer 来处理接口参数吗?

Azure 存储休息 API(放置 Blob API)

Express,第二次调用then()函数,用猫鼬保存对象后返回未定义对象