更新文档时,MongooseJS 会弄乱预先导入的数据
MongooseJS messes up pre-imported data when document is updated
我的一段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。可以看到发送的数据没有问题。这就是 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 文档添加的。关于如何开始找出发生这种情况的原因的任何建议都会很棒。
尝试将_.merge
更改为_.extend
,然后在findById()
方法返回的thing
文档上直接调用save而不是合并对象 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);
});
});
}
另一种选择是在实体上使用 set 方法,即 thing.set(req.body)
,然后在 thing
对象上调用保存方法。
ShitalShah 的 answer 突出显示了合并和扩展之间的差异,这些差异导致合并后的结果对象中出现重复项,但本质上:
Here's how extend/assign works: For each property in source, copy its
value as-is to destination. if property values themselves are objects,
there is no recursive traversal of their properties. Entire object
would be taken from source and set in to destination.
Here's how merge works: For each property in source, check if that
property is object itself. If it is then go down recursively and try
to map child object properties from source to destination. So
essentially we merge object hierarchy from source to destination.
While for extend/assign, it's simple one level copy of properties from
source to destination.
JSBin来说明区别
我的一段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。可以看到发送的数据没有问题。这就是 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 文档添加的。关于如何开始找出发生这种情况的原因的任何建议都会很棒。
尝试将_.merge
更改为_.extend
,然后在findById()
方法返回的thing
文档上直接调用save而不是合并对象 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);
});
});
}
另一种选择是在实体上使用 set 方法,即 thing.set(req.body)
,然后在 thing
对象上调用保存方法。
ShitalShah 的 answer 突出显示了合并和扩展之间的差异,这些差异导致合并后的结果对象中出现重复项,但本质上:
Here's how extend/assign works: For each property in source, copy its value as-is to destination. if property values themselves are objects, there is no recursive traversal of their properties. Entire object would be taken from source and set in to destination.
Here's how merge works: For each property in source, check if that property is object itself. If it is then go down recursively and try to map child object properties from source to destination. So essentially we merge object hierarchy from source to destination. While for extend/assign, it's simple one level copy of properties from source to destination.
JSBin来说明区别