【问题标题】:NodeJS + Mongoose: Updating all fields on a Mongoose modelNodeJS + Mongoose:更新 Mongoose 模型上的所有字段
【发布时间】:2012-03-11 07:19:17
【问题描述】:

我正在使用 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();
...

但是,您似乎必须制定更新查询并在模型对象而不是文档对象上运行它。除非您想分配单个属性并在最后运行 save()。

有什么方法可以在不编写 Mongo 查询的情况下完成此任务?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    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();
        ...
    

    【讨论】:

    • 事后看来,.reduce 不需要使用下划线的库
    • 我一直在尝试更新对象数组中的一项。由于某种原因,markModified 方法不起作用。你的方法效果很好。
    • 谢谢@justin!你让我开心!很好的答案,@james 应该将其标记为“正确答案”。您的回答解决了我更新嵌套对象的问题。我只有一个注释。您将“util”定义为包含您的方法的变量,然后将其用作“utils”。
    • 谢谢,这太棒了,但是我必须问一个问题,如果该字段由 updatedDate 组成,那么我还必须通过 updatedDate= new Date() 在模式中更新日期,然后如何执行以及在哪里在utility.js文件中添加这个
    【解决方案2】:

    也许自从第一次提出这个问题以来这已经改变了,但是您可以使用 set 方法 ike 更新 Mongoose 中的多个路径:

    // object
    doc.set({
      path  : value,
      path2 : {
        path  : value
      }
    });
    doc.save();
    

    参考文献

    【讨论】:

      【解决方案3】:

      根据本文档不建议直接更新: 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();
           }
        });
      

      【讨论】:

      • 完美运行,我做了一个通用函数,可以在任何地方使用:
      • 在嵌套对象之前效果很好。 justin 有更完整的方法。
      • 想象一下,当一个字段被明确地留空(cleared)时,它不会被你的代码更新,而旧的值会被保留。
      【解决方案4】:

      如果你想更新整个文档,你可以根据它的 id 删除文档并重新存储整个对象。 该对象必须包含 mongo 文档的每个字段的数据。

      这是一个例子。

      mongoDBCollectionObject.findOneAndRemove({ // -- it will delete the entire document
        _id: req.body.fieldsdata._id  // here fiedsdata is exact copy with modification  of previous data
        }, function(err, data) {
        var newFieldsData = new mongoDBCollectionObject(fieldsdata); //-- fieldsdata updated data
        newFieldsData.save(function(err, data) { // save document to that collection with updated data
          if (err) {
            console.log(err);
          } else
              res.json({
                success: true
                });
          });
        })

      【讨论】:

      • 您能否提供一些示例、提示或文档来执行此操作?
      • @dakab : 我已经用示例代码更新了帖子。你可以参考它。
      【解决方案5】:

      为了澄清这个问题,您似乎正在使用请求参数并使用这些参数来查找更新给定的文档。

      有什么方法可以在不编写 Mongo 查询的情况下完成此任务?

      显而易见的答案是使用请求中的值更新模型对象。这是你的建议......

      除非您想分配单个属性并在最后运行 save()。

      但您似乎不想这样做?听起来您想直接从 Request 对象更新 Model 对象?

      如果你真的想要,你可以这样做。您只需遍历 req.params 并在适当的地方设置 doc 值。

      for(var i in req.params) {
        if(req.params[i] != doc[i]){
          doc[i] = req.params[i];
        }
      }
      

      应该就这么简单。但是,您只有想要在 Model 对象上有一大堆验证代码时这样做。模型的重点是您不想在数据库中获取随机数据。上面的行通常会“设置”正确的值,但您肯定需要围绕这个简单的for 循环包含用于身份验证、授权和验证的代码。

      【讨论】:

        【解决方案6】:

        尝试在没有找到的情况下更新集合,像这样

        Record.update({_id:req.params.id}, {$set: { field: request.field }}, {upsert: true}, function(err{...})
        

        如果不存在,则选项 upsert 创建文档。

        【讨论】:

        • 我很惊讶!,mongoError:最大调用堆栈超出了您的解决方案解决的问题
        【解决方案7】:

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

        1. 找到对象
        2. 获取所有架构路径(字段)
        3. 保存新对象。

        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)
        	});
        })

        【讨论】:

          【解决方案8】:

          使用async awaitfindOneAndRemove 以及create 是一种简洁明了的方法,这是示例代码

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

          别忘了将整个函数标记为 async

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-28
            • 1970-01-01
            • 2020-07-09
            • 2015-03-28
            • 2018-08-31
            • 2015-10-06
            • 2017-10-22
            • 2021-07-09
            相关资源
            最近更新 更多