You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js无法插入MongoDB特定JSON对象的问题求助

问题:MongoDB特殊类型(ObjectId/ISODate)导致Node.js插入报错

我写了一段Node.js代码,用来读取指定文件夹里的文件,把文件中存储的MongoDB文档插入到数据库中,但运行时出现了报错。

我的代码如下:

var fs = require("fs") 
var MongoClient = require('mongodb').MongoClient; 
var url = "mongodb://localhost:27017/"; 

MongoClient.connect(url, function(err, db) { 
  if (err) throw err; 
  var dbo = db.db("mydb"); 
  const testFolder = 'dbbackups'; 

  fs.readdir(testFolder, (err, files) => { 
    files.forEach(file => { 
      fs.readFile(testFolder+"/"+file, 'utf8', function (err,data) { 
        if (err) { return console.log(err); } 
        console.log("************************************************"); 
        console.log(file); 
        console.log(data); 
        console.log("************************************************"); 
        var dbo = db.db("mydb"); 
        var myobj = data; 
        dbo.collection(file.slice(0, -4)).insertOne(myobj, function(err, res) { 
          if (err) throw err; 
          console.log("1 document inserted"); 
          db.close(); 
        }); 
      }); 
    }); 
  }); 
});

文件中的MongoDB文档示例:

{ 
  "_id" : ObjectId("5a8be310e08d2d9fc276a3ac"), 
  "name" : "facener", 
  "firstname" : "facener", 
  "lastname" : "facener", 
  "username" : "facener", 
  "password" : "$2a$10$nWPLXb4p5wEWvk3g.YRdfOw7d1kAvPuvd45P.1AEaJyv9E0TtZfAe", 
  "multi_login" : true, 
  "phoneNumber" : { "verified" : false, "type" : "phone", "contact" : "077441234567" }, 
  "email" : { "verified" : true, "type" : "phone", "contact" : "facener" }, 
  "user_meta" : { "role" : "superadmin" }, 
  "systemuser" : true, 
  "company" : 1, 
  "tenant" : 1, 
  "client_scopes" : [ { "consoleName" : "OPERATOR", "menus" : [ { "menuItem" : "TENANTMONITOR", "menuAction" : [ { "scope" : "tenant", "read" : true, "write" : true, "delete" : true } ] } ] } ], 
  "user_scopes" : [], 
  "contacts" : [], 
  "__v" : 0, 
  "birthday" : ISODate("1989-12-24T00:00:00.000Z"), 
  "gender" : "male", 
  "avatar" : "", 
  "address" : { "number" : "77", "street" : "7 Road", "city" : "7 03", "province" : "pp", "country" : "usa", "zipcode" : "00300" }, 
  "verified" : true, 
  "group" : ObjectId("58466e3e9e5db600019768bb"), 
  "locale" : "en", 
  "app_meta" : { "subject" : "test2", "priority" : "urgent", "description" : "test2" }, 
  "Active" : true, 
  "security_level" : 1 
}

运行时的报错信息:

if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk(); 
^ TypeError: Cannot create property '_id' on string '{ "_id" : ObjectId("590091708ef913c5096e5494"),

我知道问题出在文件内容里包含了MongoDB的特定对象(比如ObjectId、ISODate),但不知道该怎么解决。想请教下这类场景的最优处理方式是什么?Node.js里有没有方法可以直接使用MongoDB兼容的JSON对象?


解决方案

首先得明确:你现在的核心问题是把文件里的字符串直接传给了insertOne,MongoDB的驱动没法把包含ObjectId、ISODate这类特殊BSON类型的字符串直接转换成对应的对象,所以才会报错说不能在字符串上创建_id属性。下面给你几个不同场景的解决方案:

1. 快速临时方案:用eval(不推荐生产用)

如果只是临时跑个脚本,而且能保证文件内容绝对安全,可以用eval把字符串解析成JS对象——因为这些ObjectId()、ISODate()本质上是MongoDB的构造函数调用,eval能直接执行它们:

// 替换原来的 var myobj = data;
const myobj = eval(`(${data})`);

⚠️ 注意:这个方法非常危险,如果文件里有恶意代码,eval会直接执行,所以绝对不要在生产环境或者处理不可信文件时用。

2. 推荐脚本方案:使用mongodb-extended-json库

MongoDB官方有个专门处理扩展JSON的库,能完美解析包含ObjectId、ISODate这类特殊类型的字符串,转换成驱动能识别的BSON对象。

步骤如下:

  • 先安装依赖:
npm install mongodb-extended-json
  • 修改你的代码:
const fs = require("fs") 
const MongoClient = require('mongodb').MongoClient; 
const EJSON = require('mongodb-extended-json'); // 引入库
const url = "mongodb://localhost:27017/"; 

MongoClient.connect(url, function(err, db) { 
  if (err) throw err; 
  const dbo = db.db("mydb"); 
  const testFolder = 'dbbackups'; 

  fs.readdir(testFolder, (err, files) => { 
    // 用计数器跟踪所有文件处理完成,避免提前关闭数据库
    let completed = 0;
    const totalFiles = files.length;

    files.forEach(file => { 
      fs.readFile(`${testFolder}/${file}`, 'utf8', function (err,data) { 
        if (err) { 
          console.log(err);
          completed++;
          if (completed === totalFiles) db.close();
          return; 
        } 
        
        console.log("************************************************"); 
        console.log(file); 
        console.log(data); 
        console.log("************************************************"); 

        // 解析扩展JSON
        const myobj = EJSON.parse(data);
        dbo.collection(file.slice(0, -4)).insertOne(myobj, function(err, res) { 
          if (err) throw err; 
          console.log("1 document inserted"); 
          completed++;
          // 所有文件处理完再关闭数据库
          if (completed === totalFiles) db.close();
        }); 
      }); 
    }); 
  }); 
});

另外还要注意:你原来的代码在insertOne回调里直接调用db.close(),这会导致第一个文件插入完成就关闭数据库,后面的文件都会报错。上面的代码加了计数器,所有文件处理完才关闭连接,解决了这个问题。

3. 最优生产方案:用官方mongorestore工具

如果你的场景是备份恢复,那完全没必要自己写代码——MongoDB官方提供的mongorestore工具就是专门干这个的,它能自动识别所有BSON特殊类型,效率更高,稳定性也更强。

只需要在命令行里运行:

mongorestore --db mydb dbbackups/

这里dbbackups是你存放备份文件的文件夹,工具会自动把每个文件(去掉后缀)对应到集合,把文件里的内容插入到对应的集合中,全程不用写一行代码。


总结一下:如果是临时脚本,用mongodb-extended-json;如果是生产环境的备份恢复,直接用mongorestore是最优解,省心又靠谱。

内容的提问来源于stack exchange,提问作者gamage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:12