我正在使用Node,MongoDB和Mongoose构建一个api。困扰我的一件事是你似乎无法一次设置多个字段:
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
doc.update(req.params);
doc.save();
...
但是,您似乎必须计算更新查询并在Model对象上而不是在文档对象上运行它。除非你想分配单个属性并在最后运行save()。
有没有办法在不编写Mongo查询的情况下完成此操作?
答案 0 :(得分:12)
jsaak的答案很好但不适用于嵌套对象。我通过搜索和设置嵌套对象详细阐述了他的答案。
我将这些函数添加到utility.js文件
var _ = require('underscore');
exports.updateDocument = function(doc, SchemaTarget, data) {
for (var field in SchemaTarget.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
var newValue = getObjValue(field, data);
console.log('data[' + field + '] = ' + newValue);
if (newValue !== undefined) {
setObjValue(field, doc, newValue);
}
}
}
return doc;
};
function getObjValue(field, data) {
return _.reduce(field.split("."), function(obj, f) {
if(obj) return obj[f];
}, data);
}
function setObjValue(field, data, value) {
var fieldArr = field.split('.');
return _.reduce(fieldArr, function(o, f, i) {
if(i == fieldArr.length-1) {
o[f] = value;
} else {
if(!o[f]) o[f] = {};
}
return o[f];
}, data);
}
实施为:
var util = require('./utility');
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
utils.updateDocument(doc, Record, req.params);
doc.save();
...
答案 1 :(得分:10)
自从第一次提出此问题以来,这可能已经发生了变化,但您可以使用set
方法更新Mongoose中的多个路径:
// object
doc.set({
path : value,
path2 : {
path : value
}
});
doc.save();
答案 2 :(得分:8)
根据本文档,不建议直接更新: http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html
我解决了这个问题: Book.findOne({isbn: req.params.isbn}, function (err, book){
if (err) {
res.send(422,'update failed');
} else {
//update fields
for (var field in Book.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
if (req.body[field] !== undefined) {
book[field] = req.body[field];
}
}
}
book.save();
}
});
答案 3 :(得分:3)
如果要更新整个文档,可以根据其ID删除文档并再次存储整个对象。 该对象必须包含mongo文档的每个字段的数据。
这是一个例子。
if smth
it = 1:5
else
it = 5:-1:1
end
for i=it
a(i)
end
答案 4 :(得分:2)
为了澄清这个问题,看起来您正在使用Request参数并使用它们来查找和更新给定文档。
有没有办法在不编写Mongo查询的情况下完成此操作?
显而易见的答案是使用Request中的值更新Model对象。这是你的建议...
除非你想分配单个属性并在最后运行save()。
但似乎你不想这样做?听起来你想直接从Request对象更新Model对象?
如果你真的想要,你可以这样做。您只需遍历req.params
并在适当的位置设置doc
值。
for(var i in req.params) {
if(req.params[i] != doc[i]){
doc[i] = req.params[i];
}
}
应该这么简单。但是,如果在Model对象上有大量验证代码,则仅要执行此操作。模型的重点是您不希望在DB中获取随机数据。上面的行通常会“设置”正确的值,但您肯定需要在简单的for
循环中包含用于身份验证,授权和验证的代码。
答案 5 :(得分:2)
尝试更新没有find的集合,比如
Record.update({_id:req.params.id}, {$set: { field: request.field }}, {upsert: true}, function(err{...})
如果不存在,选项upsert会创建文档。
答案 6 :(得分:1)
如果您有一个新对象并想要更新数据库中的整个对象,您可以像这样一次更新多个字段:
SomeModel.findOne({ 'id': 'yourid' },function (err, oldObject) {
if (err) return handleError(err);
// get all schema paths (fields)
SomeModel.schema.eachPath(function(path) {
// leave __id and __v alone
if (path != '_id' && path != '__v') {
// update the data from new object
oldObject[path] = newObject[path];
}
})
oldObject.save(function(err) {
if (err)
console.log(err)
});
})
答案 7 :(得分:0)
一种整洁的方法是使用async
await
和findOneAndRemove
以及create
,这是示例代码
try {
let resp = await this.findOneAndRemove({ _id: req.body._id });
let entry = await this.create(req.body);
} catch (err) {
}
不要忘记将整个功能标记为 async