我正在尝试使用以下代码更新MongoDB文档:
exports.update = function (req, res) {
if (req.body._id) { delete req.body._id; }
Product.findById(req.params.id, function (err, product) {
if (err) { return handleError(res, err); }
if (!product) { return res.send(404); }
var updated = _.merge(product, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.status(200).json(product);
});
});
};
代码执行成功,但.save不会更新现有的数据库数组值。 req.body的内容如下(特别注意“start”数组中的值):
{
"_id" : ObjectId("563a95d9cc2d38622b867ecf"),
"productName" : "Product Name",
"productVersion" : "1",
"productOverview" : "Description of product.",
"productManager" : ObjectId("563a90de195e72712a197d06"),
"businessPriority" : "1 Must Do",
"businessRank" : 2,
"businessFactors" : {
"growth" : true,
"diversification" : true,
"architecture" : false,
"riskMitigation" : false,
"retention" : false
},
"complete" : false,
"phase" : "Discovery",
"comment" : [
"Discovery phase comments",
"Development phase comments",
"Pilot phase comments",
"Pre-launch phase comments",
"Post-launch phase comments"
],
"finish" : [
"2015-11-30",
"2016-03-31",
"2016-05-31",
"2016-06-30",
"2016-08-31"
],
"start" : [
"2015-07-01",
"2015-12-01",
"2016-04-01",
"2016-06-01",
"2016-07-01"
]
}
.findById成功从数据库中检索现有文档,该数据库仅包含“start”数组:
{
"_id" : ObjectId("563a95d9cc2d38622b867ecf"),
"start" : [
"07-02",
"12-01",
"04-01",
"06-01",
"07-01"
]
}
lodash .merge函数构造一个正确的“更新”记录(其数据内容与上面的req.body相同)。
.save执行时没有错误,返回200状态。但是,数据库中文档的内容仍包含“start”元素的原始数据:
{
"_id" : ObjectId("563a95d9cc2d38622b867ecf"),
"start" : [
"07-02",
"12-01",
"04-01",
"06-01",
"07-01"
],
"businessFactors" : {
"growth" : true,
"diversification" : true
},
"businessPriority" : "1 Must Do",
"businessRank" : 2,
"comment" : [
"Discovery phase comments",
"Development phase comments.",
"Pilot phase comments",
"Pre-launch phase comments",
"Post-launch phase comments"
],
"finish" : [
"2015-11-30",
"2016-03-31",
"2016-05-31",
"2016-06-30",
"2016-08-31"
],
"phase" : "Discovery",
"productManager" : ObjectId("563a90de195e72712a197d06"),
"productName" : "New Product",
"productOverview" : "Description of product.",
"productVersion" : "1",
"__v" : 1
}
Mongoose Schema如下:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var productSchema = new Schema(
{
productName : String,
productVersion : String,
productOverview : String,
productManager : Schema.Types.ObjectId,
businessPriority : String,
businessRank : Number,
businessFactors : {
retention : Boolean,
growth : Boolean,
diversification : Boolean,
architecture : Boolean,
riskMitigation : Boolean
},
start : [ String ],
finish : [ String ],
comment : [ String ],
phase : String,
complete : Boolean
},
{
collection : 'products'
}
);
module.exports = mongoose.model('Product', productSchema);
有关可能发生的事情的任何指导?我在NodeJS版本4.1.1和Express版本4.13.3上使用MongoDb版本3.0.6和Mongoose版本4.1.12。
答案 0 :(得分:2)
你可以找到OneAndUndate而不是先找到id然后保存。如果id不在那里,它将创建一个新的。如果你不想让它保存一个新的设置upsert为false
Product.findOneAndUpdate({_id:<your id>, {$set: <your merged JSON>}, {upsert:true}, function(err, effected, raw){});
答案 1 :(得分:0)
尝试使用 var updated = _.assign(product, req.body);
或_.assign
代替 _.merge
:
exports.update = function (req, res) {
if (req.body._id) { delete req.body._id; }
Product.findById(req.params.id, function (err, product) {
if (err) { return handleError(res, err); }
if (!product) { return res.send(404); }
var updated = _.assign(product, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.status(200).json(product);
});
});
};
ShitalShah的 answer 突出了合并和扩展之间的差异:
以下是extend / assign的工作原理:对于源中的每个属性,复制它 价值按原样到达目的地。如果属性值本身是对象, 它们的属性没有递归遍历。整个对象 将从源头获取并设置到目的地。
以下是合并的工作原理:对于源中的每个属性,请检查是否存在 财产是对象本身。如果它然后递归下来并尝试 将子对象属性从源映射到目标。所以 基本上我们将对象层次结构从源合并到目标。 而对于extend / assign,它是简单的一级属性副本 来源目的地。
JSBin 来说明差异。
var dest = {
foo : {
b1 : "b1 value",
b2 : "b2 value"
},
baz : {
q1 : "q1 value"
},
mofo : "mofo value"
};
var src = {
foo : {
b1: "overwritten b1",
b3: "b3 value"
},
mofo : "overwritten mofo"
};
var assigned = _.clone(dest);
_.assign(assigned,src);
console.log("assign:", assigned);
var merged = _.clone(dest);
_.merge(merged,src);
console.log("merge:", merged);
var defaulted = _.clone(dest);
_.defaults(defaulted,src);
console.log("defaults:", defaulted);
pre.innerHTML = "assign: " + JSON.stringify(assigned, null, 4) + "</br>merge: " + JSON.stringify(merged, null, 4) + "</br>defaults: "+ JSON.stringify(defaulted, null, 4);
查看下面的演示。
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<pre id="pre"></pre>
public bool notify(string sender, string message)
{
var jGcmData = new JObject();
var jData = new JObject();
bool Value;
jData.Add("message", message);
jData.Add("name", sender);
jGcmData.Add("to", "/topics/global");
jGcmData.Add("data", jData);
var url = new Uri("https://gcm-http.googleapis.com/gcm/send");
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
Console.WriteLine(response);
Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
Value = true;
}
catch (Exception e)
{
Console.WriteLine("Unable to send GCM message:");
Console.Error.WriteLine(e.StackTrace);
Value = false;
}
return Value;
}