当文档被更新时,MongooseJS会调用预先导入的数据
我的一个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 URL发送一个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"} ], ...
请注意,logging数组是如何通过复制第一条logging来覆盖第二条logging的。 (如果我通过Mongoose自动添加'_id'到子文档,那么即使数组中的两个logging中的“_id”字段也是一样的)。
这可能是相关的,最初的logging不是通过Mongoose添加 – 而是通过导入JSON文件。 任何有关如何开始发现这种情况的build议都是太棒了。
尝试将_.merge
更改为_.extend
,然后直接调用findById()
方法返回的thing
文档而不是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); }); }); }
另一个select是在调用thing
对象的save方法之前,在实体上使用set方法,即thing.set(req.body)
。
这个由ShitalShah的答案突出了合并和扩展之间的差异,导致您的结果对象合并重复,但基本上重复:
以下是扩展/分配的工作原理:对于源中的每个属性,将其值原样复制到目标。 如果属性值本身是对象,则不会recursion遍历它们的属性。 整个对象将从源获取并设置到目的地。
以下是合并的工作原理:对于源代码中的每个属性,检查该属性是否是对象本身。 如果它是recursion下来,并尝试将源对象的子对象属性映射。 所以基本上我们合并了从源到目标的对象层次。 而对于扩展/分配,它是从源到目的地的简单属性级别的副本。
JSBin来说明差异