【问题标题】:Mongoose: CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"Mongoose:CastError:在路径“_id”处为值“[object Object]”转换为 ObjectId 失败
【发布时间】:2013-06-17 21:25:45
【问题描述】:

我是 node.js 的新手,所以我觉得这将是我忽略的一些愚蠢的事情,但我无法找到解决我问题的答案。我要做的是创建一个路径,该路径将创建一个新的子对象,将其添加到父对象的子数组中,然后将子对象返回给请求者。我遇到的问题是,如果我将字符串 id 传递给 findById,节点会崩溃

TypeError: Object {} has no method 'cast'

如果我尝试传入一个 ObjectId,我会得到

CastError: 路径“_id”处的值“[object Object]”转换为 ObjectId 失败

这是我的代码的粗略轮廓:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId; //Have also tried Schema.Types.ObjectId, mongoose.ObjectId

mongoose.connect('mongodb://user:password@server:port/database');

app.get('/myClass/:Id/childClass/create', function(request, result) {
  var id = new ObjectId(request.params.Id);
  MyClass.findById(id).exec( function(err, myClass) {
    if (err || !myClass) { result.send("error: " + err + "<br>" + JSON.stringify(id) || ("object '" + request.params.Id + "' not found: " + id)); return; }
    var child = ChildClass();
    myClass.Children.addToSet(child);
    myClass.save();
    result.send(child);
  });
});

如果我使用路径“/myClass/51c35e5ced18cb901d000001/childClass/create”执行此代码,这是代码的输出:

错误:CastError:在路径“_id”处为值“[object Object]”转换为 ObjectId 失败 {"path":"51c35e5ced18cb901d000001","instance":"ObjectID","validators":[],"setters":[],"getters":[],"_index":null}

我尝试使用 findOne 并传入 {_id:id} ,但这似乎正是 findById 所做的。我已经尝试过其他网站上列出的 ObjectId 的不同类。我试过像函数而不是构造函数一样调用 ObjectId() 并且返回未定义。在这一点上,我的想法已经用完了,而且谷歌搜索似乎没有帮助。关于我做错了什么有什么想法吗?

另外,就像我说的,我是 node/Mongo/Mongoose/Express 的新手,所以如果有更好的方法来实现我的目标,请告诉我。感谢所有反馈。

编辑:

在获得 Peter Lyons 的解决方法后,我在 Google 上搜索了另一个我遇到的错误并找到了 findByIdAndUpdate,它按预期工作并且完全符合我的期望。我仍然不确定为什么 findById 和 findOne 会给我这样的问题,我很想知道(可能需要提交错误报告),所以我会保持开放状态,以防其他人有答案。

【问题讨论】:

  • 我的猜测是您使用单个 ObjectId 调用 findOnefindOne 期望键/值条件的常规 JS 对象。
  • 我已经回答了这些问题here
  • 检查您的路线。可能是两条路线具有相同的起点示例“#GET /user/:userID 和 #GET /user/list”。该路由将使用“list”作为数据库的输入,并会给出一些错误。

标签: node.js mongodb mongoose


【解决方案1】:

简答:使用 mongoose.Types.ObjectId

Mongoose(但不是 mongo)可以接受对象 ID 作为字符串并为您正确“转换”它们,所以只需使用:

MyClass.findById(req.params.id)

但是,需要注意的是,如果 req.params.id 不是 mongo ID 字符串的有效格式,则会引发您必须捕获的异常。

所以要理解的主要令人困惑的事情是mongoose.SchemaTypes 具有您仅在定义猫鼬模式时使用的东西,而mongoose.Types 具有您在创建要存储在数据库或查询对象中的数据对象时使用的东西。所以mongoose.Types.ObjectId("51bb793aca2ab77a3200000d") 有效,会给你一个可以存储在数据库中或在查询中使用的对象,如果给定的 ID 字符串无效,则会抛出异常。

findOne 接受一个查询对象并将单个模型实例传递给回调。 findById 实际上是 findOne({_id: id}) (see source code here) 的包装。只需 find 接受一个查询对象并将一组匹配的模型实例传递给回调。

慢慢来。这很令人困惑,但我可以向您保证,此时您会感到困惑并且没有遇到猫鼬中的错误。这是一个相当成熟的库,但要掌握它需要一些时间。

我在您的 sn-p 中看到的另一个可疑之处是在实例化 ChildClass 时没有使用 new。除此之外,您需要发布您的架构代码,以便我们帮助您找出任何剩余的 CastErrors。

【讨论】:

  • 如果我尝试使用 "mongoose.Types.ObjectId("51c35e5ced18cb901d000001");" (通过将它直接放在代码中),我仍然收到错误“TypeError:Object {} has no method 'cast'”。我也尝试将它实例化为一个对象并得到了同样的错误。
  • 升级到最新的猫鼬?我在 3.6.11。
  • 调用 MyClass.find(req.params.id) 有效。 findOne 和 findById 不应该以相同的方式工作吗?让 find 成为当其他两个存在时返回单个文档的函数似乎有点违反直觉。我已经更改了代码以获取数组的第一项,但现在 addToSet() 失败,出现“TypeError: Object {} has no method 'cast'”。
  • 我也在 3.6.11。前几天晚上我刚刚设置了所有这些,所以我希望一切都已经是最新的了。
  • 您使用了错误的构造函数。使用mongoose.Types.ObjectIdmongoose.Schema.ObjectId 仅用于定义模式。
【解决方案2】:

我遇到了这个错误,那是因为您要在 _id 字段中过滤的值不是 ID 格式,一个“如果”应该可以解决您的错误。

const mongoose = require('mongoose');

console.log(mongoose.Types.ObjectId.isValid('53cb6b9b4f4ddef1ad47f943'));
// true
console.log(mongoose.Types.ObjectId.isValid('whatever'));
// false

要解决这个问题,请始终验证搜索条件值是否为有效的 ObjectId

const criteria = {};
criteria.$or = [];

if(params.q) {
  if(mongoose.Types.ObjectId.isValid(params.id)) {
    criteria.$or.push({ _id: params.q })
  }
  criteria.$or.push({ name: { $regex: params.q, $options: 'i' }})
  criteria.$or.push({ email: { $regex: params.q, $options: 'i' }})
  criteria.$or.push({ password: { $regex: params.q, $options: 'i' }})
}

return UserModule.find(criteria).exec(() => {
  // do stuff
})

【讨论】:

  • 正确。我正在使用findById 测试GET 用户的端点,结果id 参数必须是12 位,否则猫鼬将无法投射。我使用的是随机短数字。
【解决方案3】:

对于所有遇到此问题但仍无法解决的人:我偶然发现了同样的错误,发现 _id 字段为空。

我更详细地描述了它here。除了将_id 中的字段更改为非 ID 字段外,仍然没有找到解决方案,这对我来说是一个肮脏的黑客攻击。我可能会为猫鼬提交错误报告。任何帮助将不胜感激!

编辑:我更新了我的线程。我提交了一张票,他们确认了丢失的_id 问题。它将在 4.x.x 版本中得到修复,该版本现在有一个可用的候选版本。不建议将 rc 用于生产用途!

【讨论】:

  • 有趣,我想我也有同样的问题,我的 _id 未定义,因此无法转换为 ObjectId
【解决方案4】:

如果您遇到此问题并且您正在执行填充,see this Mongoose issue

更新到 Mongoose 4.0,问题已得到修复。

【讨论】:

    【解决方案5】:

    遇到同样的问题,我只是将 id 强制转换为字符串。

    我的架构:

    const product = new mongooseClient.Schema({
        retailerID: { type: mongoose.SchemaTypes.ObjectId, required: true, index: true }
    });
    

    然后,插入时:

    retailerID: `${retailer._id}`
    

    【讨论】:

      【解决方案6】:

      我的解决方案是我想要来自所有文档的数据,我不想要 _id,所以

      User.find({}, {_id:0, keyToShow:1, keyToNotShow:0})
      

      【讨论】:

        【解决方案7】:

        我有同样的问题,在我更新了我的架构后,我忘记了我使用我创建的旧 id 调用模型;我已经从以下内容更新了我的架构:

        patientid: {
                   type: String,
                    required: true,
                    unique: true
                  }, 
        

        patientid: { type: mongoose.SchemaTypes.ObjectId, ref: "Patient" },
        

        事实证明,由于我的代码很大,我用旧 id 调用了findOne,因此,问题出现了。

        我在这里发帖只是为了帮助其他人:请检查您的代码是否有未知的错误调用!这可能是问题所在,它可以拯救你的大脑袋!

        【讨论】:

        • 您好!这也是我的问题的解决方案!我必须在新模型上插入新数据才能正常工作。祝你有美好的一天!
        【解决方案8】:

        我收到此错误 CastError: Cast to ObjectId failed for value “[object Object]” at path “_id” 创建模式后,然后对其进行修改并且无法跟踪它。我删除了集合中的所有文档,我可以添加 1 个对象但不能添加第二个对象。我最终删除了 Mongo 中的集合,并且 Mongoose 重新创建了集合。

        【讨论】:

          【解决方案9】:

          郑重声明:我在尝试以错误的方式填写子文档时遇到此错误:

          {
          [CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"]
          message: 'Cast to ObjectId failed for value "[object Object]" at path "_id"',
          name: 'CastError',
          type: 'ObjectId',
          path: '_id'
          value:
            [ { timestamp: '2014-07-03T00:23:45-04:00',
            date_start: '2014-07-03T00:23:45-04:00',
            date_end: '2014-07-03T00:23:45-04:00',
            operation: 'Deactivation' } ],
          }
          

          看 ^ 值是一个包含对象的数组:错误!

          说明:我以这种方式将数据从 php 发送到 node.js API:

          $history = json_encode(
          array(
            array(
            'timestamp'  => date('c', time()),
            'date_start' => date('c', time()),
            'date_end'   => date('c', time()),
            'operation'  => 'Deactivation'
          )));
          

          如您所见,$history 是一个包含数组的数组。这就是为什么 mongoose 尝试用数组而不是 Scheme.ObjectId (或任何其他数据类型)填充 _id (或任何其他字段)。以下作品:

          $history = json_encode(
          array(
            'timestamp'  => date('c', time()),
            'date_start' => date('c', time()),
            'date_end'   => date('c', time()),
            'operation'  => 'Deactivation'
          ));
          

          【讨论】:

            【解决方案10】:

            我也遇到了这个猫鼬错误 CastError: Cast to ObjectId failed for value \"583fe2c488cf652d4c6b45d1\" at path 模型用户的“_id”

            所以我运行 npm list 命令来验证本地的 mongodb 和 mongoose 版本。 报告如下: ......
            ......
            ├── mongodb@2.2.19
            ├── mongoose@4.7.2
            .....

            这个 mongodb 版本似乎有问题,所以我卸载并尝试使用不同的版本,例如 2.2.16

            $ npm uninstall mongodb,它会从你的 node_modules 目录中删除 mongodb。之后安装较低版本的mongodb。
            $ npm install mongodb@2.2.16
            最后,我重新启动应用程序,CastError 消失了!!

            【讨论】:

              【解决方案11】:

              我遇到了同样的问题。原来我的 Node.js 已经过时了。升级后就可以了。

              【讨论】:

                【解决方案12】:

                我不确定这是否会有所帮助,但我通过像下面这样导入 mongoose 并按照下面的方式实现它解决了这个问题

                const mongoose = require('mongoose')
                
                _id: new mongoose.Types.ObjectId(),
                

                【讨论】:

                  【解决方案13】:

                  只需更改它将起作用的路径,例如

                  app.get('/myClass/:Id/childClass/create', function(request, result) .....
                  

                  改成

                  app.get('/myClass**es**/:Id/childClass/create', function(request, result) .....
                  

                  我刚刚在路径 (myClass) 中添加了 --es-- 以成为 (myClasses)

                  现在应该可以工作并且不会看到该错误

                  【讨论】:

                    【解决方案14】:

                    对我来说,ID 是未定义的(req.params.id 返回未定义)

                    【讨论】:

                      【解决方案15】:

                      如果您通过模型的“_id”查找文档,例如 Drivers,则以下命令运行良好:

                      ....
                      const driver = await Drivers.findById(<your id>);
                      ....
                      

                      确保使用 async-await 和 try-catch ES6 语法

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-05-11
                        • 1970-01-01
                        • 2021-03-13
                        • 2014-06-20
                        • 2017-05-19
                        • 2017-11-10
                        • 2019-01-06
                        相关资源
                        最近更新 更多