【问题标题】:Mongoose: findOneAndUpdate doesn't return updated documentMongoose:findOneAndUpdate 不返回更新的文档
【发布时间】:2018-01-15 18:09:48
【问题描述】:

下面是我的代码

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', {
    name: String,
    age: {type: Number, default: 20},
    create: {type: Date, default: Date.now} 
});

Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}},function(err, doc){
    if(err){
        console.log("Something wrong when updating data!");
    }

    console.log(doc);
});

我的 mongo 数据库中已经有一些记录,我想运行此代码来更新年龄为 17 岁的姓名,然后在代码末尾打印结果。

但是,为什么我仍然从控制台(不是修改后的名称)得到相同的结果,但是当我转到 mongo db 命令行并输入“db.cats.find();”时。结果带有修改后的名称。

然后我回去再次运行这段代码,结果被修改了。

我的问题是:如果数据被修改了,那为什么我在第一次console.log的时候还是得到了原始数据。

【问题讨论】:

  • 使用{new:true} 似乎不适用于updateOne,将updateOne 替换为findOneAndUpdate 及其工作

标签: node.js mongodb mongoose


【解决方案1】:

为什么会这样?

默认是返回原始的、未更改的文档。如果您希望返回新的更新文档,您必须传递一个附加参数:new 属性设置为 true 的对象。

来自mongoose docs

查询#findOneAndUpdate

Model.findOneAndUpdate(conditions, update, options, (error, doc) => {
  // error: any errors that occurred
  // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
});

可用选项

  • new: bool - 如果 true,返回 修改后的 文档而不是原始文档。 默认为 false(在 4.0 中更改)

解决方案

如果您希望 doc 变量中的更新结果,请传递 {new: true}

//                                                         V--- THIS WAS ADDED
Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}}, {new: true}, (err, doc) => {
    if (err) {
        console.log("Something wrong when updating data!");
    }

    console.log(doc);
});

【讨论】:

  • 这对我来说似乎坏了,它仍然返回旧文档,新:true。
  • 对我来说很有意义,因为您已经可以访问新文档
  • 它对我有用,我使用的是 moogose 版本 4.6.3,谢谢
  • 我得到了新文档,但_id 为空,所以它不是真正的新文档。
  • NodeJs MongoDB 原生使用 - { returnOriginal: false }
【解决方案2】:

默认情况下findOneAndUpdate 返回原始文档。如果您希望它返回修改后的文档,请将选项对象 { new: true } 传递给函数:

Cat.findOneAndUpdate({ age: 17 }, { $set: { name: "Naomi" } }, { new: true }, function(err, doc) {

});

【讨论】:

  • 为什么_id 为空?
【解决方案3】:

对于使用带有原生承诺的 ES6 / ES7 风格偶然发现此问题的人,您可以采用以下模式...

const user = { id: 1, name: "Fart Face 3rd"};
const userUpdate = { name: "Pizza Face" };

try {
    user = await new Promise( ( resolve, reject ) => {
        User.update( { _id: user.id }, userUpdate, { upsert: true, new: true }, ( error, obj ) => {
            if( error ) {
                console.error( JSON.stringify( error ) );
                return reject( error );
            }

            resolve( obj );
        });
    })
} catch( error ) { /* set the world on fire */ }

【讨论】:

  • 如果您不提供回调函数,Mongoose 将返回一个承诺。无需创建自己的承诺!
  • 如果您不提供回调,@joeytwiddle Mongoose 不会返回 Promise。相反,它返回一个仅提供一小部分 Promise API 的 Query 对象。这是根据猫鼬文档。
【解决方案4】:

对于使用 Node.js 驱动程序而不是 Mongoose 的任何人,您需要使用 {returnOriginal:false} 而不是 {new:true}

2021 - Mongodb ^4.2.0 更新
{ returnDocument: 'after' }

【讨论】:

  • 谢谢!这适用于我 mongodb 节点版本 2.2.27
  • 这是一种愚蠢的 API。为什么不对 Mongoose 使用与原生 API 相同的签名?为什么不默认返回更新的文档? Mongoose 是我每天使用的比较烦人的库之一。
  • 我正在使用 "mongodb": "^3.6.9"{ returnOriginal:false } 已弃用。请改用{ returnDocument: 'after' }
  • 谢谢!这对我有用。 @kunthet 我实际上正在使用它,因为文档解释说建议的 { returnOriginal: false } 已弃用。但由于某种原因,我无法让它发挥作用,而使用建议可以按预期工作。
【解决方案5】:

这是findOneAndUpdate 的更新代码。它有效。

db.collection.findOneAndUpdate(    
  { age: 17 },      
  { $set: { name: "Naomi" } },      
  {
     returnNewDocument: true
  }    
)

【讨论】:

    【解决方案6】:

    因此,“findOneAndUpdate”需要一个选项来返回原始文档。而且,选项是:

    MongoDB 外壳

    {returnNewDocument: true}

    参考:https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/

    猫鼬

    {new: true}

    参考:http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

    Node.js MongoDB 驱动 API:

    {returnOriginal: false}

    2021 - Mongodb ^4.2.0 更新
    { returnDocument: 'after' }

    参考:http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#findOneAndUpdate

    【讨论】:

    • Laravel: 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER
    【解决方案7】:

    如果你想返回修改后的文档,你需要设置选项{new:true} API参考你可以使用Cat.findOneAndUpdate(conditions, update, options, callback) // executes

    由Mongoose官方APIhttp://mongoosejs.com/docs/api.html#findoneandupdate_findOneAndUpdate拍摄,可以使用以下参数

    A.findOneAndUpdate(conditions, update, options, callback) // executes
    A.findOneAndUpdate(conditions, update, options)  // returns Query
    A.findOneAndUpdate(conditions, update, callback) // executes
    A.findOneAndUpdate(conditions, update)           // returns Query
    A.findOneAndUpdate()                             // returns Query
    

    另一个未在官方 API 页面中表达但我更喜欢使用的实现是 Promise 基本实现,它允许您拥有 .catch 在那里您可以在那里处理所有各种错误。

        let cat: catInterface = {
            name: "Naomi"
        };
    
        Cat.findOneAndUpdate({age:17}, cat,{new: true}).then((data) =>{
            if(data === null){
                throw new Error('Cat Not Found');
            }
            res.json({ message: 'Cat updated!' })
            console.log("New cat data", data);
        }).catch( (error) => {
            /*
                Deal with all your errors here with your preferred error handle middleware / method
             */
            res.status(500).json({ message: 'Some Error!' })
            console.log(error);
        });
    

    【讨论】:

      【解决方案8】:

      下面显示了对 mongoose 的findOneAndUpdate 的查询。这里new: true用于获取更新的doc,fields用于获取特定字段。

      例如。 findOneAndUpdate(conditions, update, options, callback)

      await User.findOneAndUpdate({
            "_id": data.id,
          }, { $set: { name: "Amar", designation: "Software Developer" } }, {
            new: true,
            fields: {
              'name': 1,
              'designation': 1
            }
          }).exec();
      

      【讨论】:

        【解决方案9】:

        这里是 Mongoose 的维护者。您需要将new 选项设置为true(或者,等效地,将returnOriginal 设置为false

        await User.findOneAndUpdate(filter, update, { new: true });
        
        // Equivalent
        await User.findOneAndUpdate(filter, update, { returnOriginal: false });
        

        参见Mongoose findOneAndUpdate() docsthis tutorial on updating documents in Mongoose

        【讨论】:

        • 我误写了 returnNewDocument 而不是 new。感谢您的帮助!
        • 如何在没有异步的情况下使用 await?
        • 你不能@PeterXX 那只是一个代码sn-p。
        【解决方案10】:

        我知道,我已经迟到了,但让我在这里添加我的简单有效答案

        const query = {} //your query here
        const update = {} //your update in json here
        const option = {new: true} //will return updated document
        
        const user = await User.findOneAndUpdate(query , update, option)
        

        【讨论】:

          【解决方案11】:

          在某些情况下{new: true} 不起作用。 那你可以试试这个。

          {'returnNewDocument':true}
          

          【讨论】:

            【解决方案12】:

            2021 - Mongodb ^4.2.0 更新

            这适用于 mongodb 节点驱动程序,NOT mongoose。

            如果您使用“collection.findOneAndUpdate”进行搜索和更新,最新版本的 Mongodb 节点驱动程序似乎使用以下语法:

            .findOneAndUpdate(query, update, { returnDocument: 'after' | 'before' })
            

            我自己在搜索时无法在这里找到答案,所以发布这个以防其他人处于同样的情况。

            【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-07-03
            • 2018-07-10
            • 1970-01-01
            • 2020-05-13
            • 2014-09-04
            相关资源
            最近更新 更多