Mongoose实例的.save()方法无法工作

36

我在Mongoose和MongoDb方面遇到了问题。

有趣的是,只有Model.update有效,而save从不起作用,甚至不触发回调。

Mongoose: 4.4.5 MongoDB: 3.0.8

Express路由

var mongoose = require('mongoose');
mongoose.connect("mongodb://127.0.0.1:27017/db");
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function(callback) {
    console.log("connection to db open")
});
var User = require("../models/user.js");

用户模型

var user = new Schema({
    uid: { type: Number, required: true, unique: true},
    hwid: { type: String, default:""},
    bol:{type:String,default:""}
});

更新端点

工作版本:Model.update()

User.update({_id: id}, {
    uid: 5, 
}, function(err, numberAffected, rawResponse) {
    console.log(err);
})

出现问题的版本,我需要解决这个问题:Object.save()

User.find({_id:id}, function(err,user){
    if(err){
         console.log(err);
    }
    if(!user){
         console.log("No user");
    }else{
        user.uid = 5;
        user.save(function(err,news){
            console.log("Tried to save...");
        });
    }
    console.log("At least worked");
})

即使回调函数没有触发,连接也成功打开。它从未调用回调函数。


  1. 尝试使用var User = connection.model('User', schema)没有起作用。

我知道你的评论说它是一个mongo对象,但是说实话,在你展示的内容中并没有任何证据证明这一点,这很可能是你的“.save”方法没有触发的原因。你是如何验证它是从数据库返回的实际实例的呢? - Paul
@Paul,我更新了问题,请您查看。 - Ahmet Can Güven
当你在.find()回调函数中使用console.log(user)时会发生什么? - Jesse Kernaghan
1
@JesseKernaghan 没有任何反应,它没有调用回调函数。 - Ahmet Can Güven
@JesseKernaghan,@Paul 感谢你们的帮助,我已经自己解决了问题。只是犯了一个新手错误。 - Ahmet Can Güven
显示剩余3条评论
9个回答

116

我遇到了同样的问题。我的问题是关于在数据库内更改数组,当我尝试使用.save()时,它没有理解我改变了任何东西,所以.save()无法工作。 在使用.save()之前,我只需使用markModified(),我的问题就得到了解决。

这是我的有问题的代码:(不起作用)

club.members[index].name = new_name;
club.save();

这是我的解决方案代码:(可正常工作)

club.members[index].name = new_name;
club.markModified('members');
club.save();

享受!


2
我的问题很相似,但改动不够明确。不要试图像这样聪明地写代码: document.keys = { ...document.keys, ...updates } 相反,逐个应用所有的改动。 - remidej
1
哇,这真是太有帮助了!我一直在使用一个变异函数来修改数组的内容,但Mongoose没有捕捉到它们。这个答案结束了几个小时的错误追踪。 - Andy
1
还修复了在更新Map中的某些嵌套属性时出现的问题。 - eOf
1
这对我有用。非常感谢!也适用于对象,不仅仅是数组。 - IronmanX46
1
在MongoDB中有很多不明显的问题,导致每个人都浪费了他们的时间! - Rounak Jain
显示剩余4条评论

32

我不会删除这个问题,因为其他人可能也会遇到这个问题。实际上,这个问题与MongoDb或Mongoose无关。当您调用 Object.save() 时,责任链如下:

  1. Schema.pre("save")
  2. 将数据保存到数据库
  3. Schema.post("save")

因此,如果您阻止 pre("save") 并且不调用 next() 处理程序,您将无法保存文档。这就是我的情况,我忘记了在 if 语句中调用 next() ,并试图查找错误超过3个小时。

user.pre("save", function(next) {
    if(!this.trial){
        //do your job here
        next();
    }
}

this.trial == true时,下一个处理程序将无法到达。

为了避免这样的错误,我们应该注意分支覆盖率,报告可以显示未经测试的代码。你的问题也可能与此有关。 请确保在文档应该保存时调用next()

已修复版本

user.pre("save", function(next) {
    if(!this.trial){
        //do your job here
    }
    next();
}

12
我们来实际一点,注意到你的问题本身没有提到“预保存挂钩”,因此这并不是任何人会想到的解决方案。当然,如果中间件继续未被调用,那么代码将被卡住而无法继续。这些实际上是“回调函数”而不是“承诺”。 - Blakes Seven
2
感谢您挽救了我的理智...我也遇到了同样的问题,浪费了将近3个小时来弄清楚到底出了什么问题... - Carlos

12
这听起来很疯狂...我已经花了几个小时来解决这个问题。看了这么多的堆栈溢出帖子....真不可思议。
而你知道问题出在哪里吗?我没有在URL结尾指定数据库。
所以,代替

您可以:
"mongodb://127.0.0.1:27017/test"

我有

"mongodb://127.0.0.1:27017

我在这个问题上浪费了一整天的时间。我真希望能得到某些错误提示。保存记录时总是返回 ok,数据库日志中也显示连接成功。但我真的需要查看详细信息。是的,它连接到了 mongo 实例,但没有连接到数据库本身。唉!


哦,老兄,你在2020年救了我的命 :D 谢谢。我也犯了同样的错误,在那里忘记添加数据库名称。 - Deniz Bayar
在我的情况下,问题是<数据库名称>,而且我在<密码>中留下了<>,就像这样。我当时真是太愚蠢了。哈哈 - Freakant

5

就像Paul所说的那样。最有可能的是你正在对'req.user'对象调用save方法,而它不是一个Mongoose对象。确保你正在做类似于这样的事情:

//I am using your 'user' schema
var userModel = mongoose.model('User', user);
var User = mongoose.model('User');
var newUser = new User(req.user);
newUser.save(function(error, user){
   //your code
}

3
不行,我确定.save()有问题。 - Ahmet Can Güven

2
< p > < em > 以防万一其他人也遇到了这个问题。 < p > 另一个可能的原因是您没有与mongodb实例建立开放连接。检查输出以获取适当的连接反馈。 < blockquote > < p> [initandlisten]从127.0.0.1:40448接受的连接#1(现在打开1个连接)

耶稣感谢您...我卡在这里大约20分钟了。 - Danny Boris Ov

1
我遇到了同样的问题,原来 instance.save() 返回一个 Promise。所以你只需要处理这个 Promise。 使用 async/await-
await instance.save()

0

modlename.save() 不再接受回调函数,现在您可以使用 Promises 来解决这个问题。

newData.save().then(function(err) {
  if (!err) {
    res.send("Successfully Added to th DataBase.");
  } else {
    res.send(err);
  }
});


0

现在使用if else语句对save()方法不起作用。我认为你可以使用try catch语句来解决这个问题。

user.save().then(function (err) {
    try {
      res.render("User created succesfully");
    } catch (err) {
      console.log(err);
    }
  });

嗨,作者在评论中指定他已经找到了解决方案。回答时,请仔细阅读所有评论。无论如何,我要求作者写一个常规答案。请看这里:如何回答 - pierpy

-2

对于任何遇到和我一样的错误的人... 如果你在非常短的时间内调用.save()两次,最后一次调用将被丢弃。 我的问题就是这个。

//module usersave(userData)
{
  await userData.save()
}
//module A
{...todos
  moduleB(userData)
  ...some todos that doesn't take much time.
  await usersave(userData) //second call
}
//module B(userData)
{
 ...todos;
 await usersave(userData) // first call
}

=> 在模块B中调用了Object.save(),然后立即在模块A中再次调用。 (无论你是在save模块中实现还是直接调用Object.save())。 这种调用堆栈不会产生错误,并且两个模块都将正常成功返回。 然而,由于第二次调用在mongodb实际反映更改之前被唤起,因此稍后的调用就会被忽略。 问题在于它返回好像它们实际上已经保存了,所以你无法捕获错误。

解决方法:只需加上await。 await new Promise(r=>setTimeout(r,2000))即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接