当文档更新时,MongooseJS会混乱预先导入的数据

时间:2015-04-12 16:12:42

标签: node.js mongodb mongoose

我的Mongo文档结构是:

{ "_id": ObjectId("xxxxxx..."),
"Country" : "UNITED KINGDOM", 
"Line" : "something",
"Records" : [
     {"rdata" : "foo", "rtype" : "X", "name" : "John"}, 
     {"rdata" :  "bar", "rtype" : "Y", "name" : "Bill"}
],  ...

我正在使用Mongoose通过以下模型访问数据:

var Record = new Schema({
 rdata: String,
 rtype: String,
 name:  String
}, {_id: false});

var ThingSchema = new Schema({
Country: String,
Line : String,
Records : [Record],

假设我要通过向相应的API网址发送PUT请求来更新我的某个文档的“Line”属性,从"Line" : "something""Line" : "way more interesting"。我可以看到发送的数据没问题。这就是API的作用:

exports.update = function(req, res) {
  if(req.body._id) { delete req.body._id; }
  Thing.findById(req.params.id, function (err, thing) {
    if (err) { return handleError(res, err); }
    if(!thing) { return res.send(404); }
    var updated = _.merge(thing, req.body);
    updated.save(function (err) {
      if (err) { return handleError(res, err); }
      return res.json(200, updated);
    });
  });
};

API以200 / OK返回 - 但我看到以下更新数据:

{ "_id": ObjectId("xxxxxx..."),
"Country" : "UNITED KINGDOM", 
"Line" : "way more interesting",  <-- updated correctly
"Records" : [
     {"rdata" : "foo", "rtype" : "X", "name" : "John"}, 
     {"rdata" :  "foo", "rtype" : "X", "name" : "John"}
],  ...

注意,如何通过复制第一个记录来覆盖我的第二个记录,从而弄乱了Records数组。 (如果我通过Mongoose打开自动添加'_id'到子文档,那么即使“_id”字段在数组中的两个记录上也是相同的。)

可能相关的是,最初的记录不是通过Mongoose添加的 - 而是通过导入JSON文档。关于如何开始找出这种情况发生的任何建议都会很棒。

1 个答案:

答案 0 :(得分:2)

尝试将_.merge更改为_.extend,然后直接在 thing 方法而不是合并对象返回的findById()文档上调用保存updated

exports.update = function(req, res) {
    if(req.body._id) { delete req.body._id; }
    Thing.findById(req.params.id, function (err, thing) {
        if (err) { return handleError(res, err); }
        if(!thing) { return res.send(404); }
         _.extend(thing, req.body);
        thing.save(function (err) {
            if (err) { return handleError(res, err); }
            return res.json(200, thing);
        });
    });
}

另一个选择是在thing.set(req.body)对象上调用save方法之前在实体上使用set方法,即thing

ShitalShah的 answer 突出显示了合并和扩展之间的差异,这种差异导致合并后的对象产生重复,但基本上是:

  

以下是extend / assign的工作原理:对于源中的每个属性,复制它   价值按原样到达目的地。如果属性值本身是对象,   它们的属性没有递归遍历。整个对象   将从源头获取并设置到目的地。

     

以下是合并的工作原理:对于源中的每个属性,请检查是否存在   财产是对象本身。如果它然后递归下来并尝试   将子对象属性从源映射到目标。所以   基本上我们将对象层次结构从源合并到目标。   而对于extend / assign,它是简单的一级属性副本   来源目的地。

JSBin 来说明差异