MongoDB更新了对象,项目删除不保存

时间:2015-08-31 10:13:06

标签: javascript angularjs node.js mongodb

我正在使用Angular Fullstack作为网络应用。

我通过$http.post()我的对象发布我的数据:

{ title: "Some title", tags: ["tag1", "tag2", "tag3"] }

当我编辑我的对象并尝试$http.put()时,例如:

{ title: "Some title", tags: ["tag1"] }

在控制台中我得到HTTP PUT 200但是当我刷新页面时,我仍然使用所有3个标签来回放该对象。

这是我在MongoDB中保存的方式:

exports.update = function(req, res) {
  if (req.body._id) {
    delete req.body._id;
  }

  Question.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(saveUpdates(req.body))
    .then(responseWithResult(res))
    .catch(handleError(res));
};


function saveUpdates(updates) {

  return function(entity) {

    var data = _.merge(entity.toJSON(), updates);
    var updated = _.extend(entity, data);

    return updated.saveAsync()
      .spread(function(updated) {
        return updated;
      });
  };
}

有人可以解释如何使用已删除的项目保存对象吗?

我做错了什么?

1 个答案:

答案 0 :(得分:1)

从数据库中检索后,在客户端(意味着你的nodejs客户端是数据库而不是浏览器)代码中使用_.merge_.extend之类的东西是非常糟糕的做法。同样值得注意的是_.merge是问题,因为它不会“带走”东西,而是“扩充”已经存在的信息。不是你想要的,但也有更好的方法。

你应该简单地使用像$set这样的“原子操作符”来代替:

Question.findByIdAndUpdateAsync(
    req.params.id,
    { "$set": { "tags": req.body.tags } },
    { "new": true }
)
.then(function(result) {
    // deal with returned result
});

您还应该定位您的端点,而不是编写“通用”对象。因此,obove仅针对相关“标签”的“PUT”进行特定目标,而不是触及对象中的其他字段。

如果你真的必须抛出一个完整的对象并希望从所有内容中获得更新,那么使用帮助器来正确修复更新语句:

function dotNotate(obj,target,prefix) {
  target = target || {},
  prefix = prefix || "";

  Object.keys(obj).forEach(function(key) {
    if ( typeof(obj[key]) === "object" ) {
      dotNotate(obj[key],target,prefix + key + ".");
    } else {
      return target[prefix + key] = obj[key];
    }
  });

  return target;
}

var update = { "$set": dotNotate(req.body) };

Question.findByIdAndUpdateAsync(
    req.params.id,
    update,
    { "new": true }
)
.then(function(result) {
    // deal with returned result
});

哪个正确的结构无关紧要你扔在它上面的对象。

虽然在这种情况下,可能只是直接就足够了:

Question.findByIdAndUpdateAsync(
    req.params.id,
    { "$set": req.body },
    { "new": true }
)
.then(function(result) {
    // deal with returned result
});

还有其他原子操作符的方法,您也可以适合您的逻辑进行处理。但最好考虑每个元素执行这些操作,至少是根文档属性,以及像孩子一样单独处理的数组。

所有原子操作都与“在数据库中”和“在修改时”的文档进行交互。从数据库中提取数据,对其进行修改,然后保存回来,不会提供数据尚未更改的相关数据,并且您可能正在覆盖已经发布的其他更改。

我说你的“浏览器客户端”应该已经知道“tags”数组有另外两个条目然后你的“修改请求”应该只是$pull要从数组中删除的条目,像这样:

Question.findByIdAndUpdateAsync(
    req.params.id,
    { "$pull": { "tags": { "$in": ["tag2", "tag3"] } } },
    { "new": true }
)
.then(function(result) {
    // deal with returned result
});

然后,“无论”修改时服务器上文档的当前状态如何,这些更改将是唯一的。因此,如果在添加“tag4”时修改了其他内容,并且客户端在发送修改之前尚未获得此类更改的信息,那么返回响应也将包括该内容,并且所有内容都将同步。

了解MongoDB的update modifiers,因为它们可以很好地为您服务。