NodeJS + Mongoose:更新Mongoose模型上的所有字段

时间:2012-02-20 23:06:59

标签: node.js mongodb mongoose

我正在使用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查询的情况下完成此操作?

8 个答案:

答案 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)

如果您有一个新对象并想要更新数据库中的整个对象,您可以像这样一次更新多个字段:

  1. 找到对象
  2. 获取所有架构路径(字段)
  3. 保存新对象。
  4. 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 awaitfindOneAndRemove以及create,这是示例代码

try {
            let resp = await this.findOneAndRemove({ _id: req.body._id });
            let entry = await this.create(req.body);

    } catch (err) {

    }

不要忘记将整个功能标记为 async